Skip to content

Commit

Permalink
[clang/asan] call __asan_poison_cxx_array_cookie after operator new[]
Browse files Browse the repository at this point in the history
Summary:
PR19838
When operator new[] is called and an array cookie is created
we want asan to detect buffer overflow bugs that touch the cookie.
For that we need to
  a) poison the shadow for the array cookie (call __asan_poison_cxx_array_cookie).
  b) ignore the legal accesses to the cookie generated by clang (add 'nosanitize' metadata)

Reviewers: timurrrr, samsonov, rsmith

Reviewed By: rsmith

Subscribers: cfe-commits

Differential Revision: http://reviews.llvm.org/D4774

llvm-svn: 216434
  • Loading branch information
kcc committed Aug 26, 2014
1 parent b06f77b commit 4ee6904
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 10 deletions.
7 changes: 2 additions & 5 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Expand Up @@ -1683,11 +1683,8 @@ void CodeGenFunction::InsertHelper(llvm::Instruction *I,
llvm::BasicBlock *BB,
llvm::BasicBlock::iterator InsertPt) const {
LoopStack.InsertHelper(I);
if (IsSanitizerScope) {
I->setMetadata(
CGM.getModule().getMDKindID("nosanitize"),
llvm::MDNode::get(CGM.getLLVMContext(), ArrayRef<llvm::Value *>()));
}
if (IsSanitizerScope)
CGM.getSanitizerMetadata()->disableSanitizerForInstruction(I);
}

template <bool PreserveNames>
Expand Down
22 changes: 17 additions & 5 deletions clang/lib/CodeGen/ItaniumCXXABI.cpp
Expand Up @@ -1472,10 +1472,19 @@ llvm::Value *ItaniumCXXABI::InitializeArrayCookie(CodeGenFunction &CGF,
CookieOffset.getQuantity());

// Write the number of elements into the appropriate slot.
llvm::Value *NumElementsPtr
= CGF.Builder.CreateBitCast(CookiePtr,
CGF.ConvertType(SizeTy)->getPointerTo(AS));
CGF.Builder.CreateStore(NumElements, NumElementsPtr);
llvm::Type *NumElementsTy = CGF.ConvertType(SizeTy)->getPointerTo(AS);
llvm::Value *NumElementsPtr =
CGF.Builder.CreateBitCast(CookiePtr, NumElementsTy);
llvm::Instruction *SI = CGF.Builder.CreateStore(NumElements, NumElementsPtr);
if (CGM.getLangOpts().Sanitize.Address &&
expr->getOperatorNew()->isReplaceableGlobalAllocationFunction()) {
CGM.getSanitizerMetadata()->disableSanitizerForInstruction(SI);
llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.VoidTy, NumElementsTy, false);
llvm::Constant *F =
CGM.CreateRuntimeFunction(FTy, "__asan_poison_cxx_array_cookie");
CGF.Builder.CreateCall(F, NumElementsPtr);
}

// Finally, compute a pointer to the actual data buffer by skipping
// over the cookie completely.
Expand All @@ -1498,7 +1507,10 @@ llvm::Value *ItaniumCXXABI::readArrayCookieImpl(CodeGenFunction &CGF,
unsigned AS = allocPtr->getType()->getPointerAddressSpace();
numElementsPtr =
CGF.Builder.CreateBitCast(numElementsPtr, CGF.SizeTy->getPointerTo(AS));
return CGF.Builder.CreateLoad(numElementsPtr);
llvm::Instruction *LI = CGF.Builder.CreateLoad(numElementsPtr);
if (CGM.getLangOpts().Sanitize.Address)
CGM.getSanitizerMetadata()->disableSanitizerForInstruction(LI);
return LI;
}

CharUnits ARMCXXABI::getArrayCookieSizeImpl(QualType elementType) {
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/CodeGen/SanitizerMetadata.cpp
Expand Up @@ -67,6 +67,12 @@ void SanitizerMetadata::disableSanitizerForGlobal(llvm::GlobalVariable *GV) {
reportGlobalToASan(GV, SourceLocation(), "", false, true);
}

void SanitizerMetadata::disableSanitizerForInstruction(llvm::Instruction *I) {
I->setMetadata(
CGM.getModule().getMDKindID("nosanitize"),
llvm::MDNode::get(CGM.getLLVMContext(), ArrayRef<llvm::Value *>()));
}

llvm::MDNode *SanitizerMetadata::getLocationMetadata(SourceLocation Loc) {
PresumedLoc PLoc = CGM.getContext().getSourceManager().getPresumedLoc(Loc);
if (!PLoc.isValid())
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/SanitizerMetadata.h
Expand Up @@ -18,6 +18,7 @@

namespace llvm {
class GlobalVariable;
class Instruction;
class MDNode;
}

Expand All @@ -41,6 +42,7 @@ class SanitizerMetadata {
StringRef Name, bool IsDynInit = false,
bool IsBlacklisted = false);
void disableSanitizerForGlobal(llvm::GlobalVariable *GV);
void disableSanitizerForInstruction(llvm::Instruction *I);
private:
llvm::MDNode *getLocationMetadata(SourceLocation Loc);
};
Expand Down
54 changes: 54 additions & 0 deletions clang/test/CodeGen/address-sanitizer-and-array-cookie.cpp
@@ -0,0 +1,54 @@
// RUN: %clang_cc1 -triple x86_64-gnu-linux -emit-llvm -o - %s | FileCheck %s -check-prefix=PLAIN
// RUN: %clang_cc1 -triple x86_64-gnu-linux -emit-llvm -o - -fsanitize=address %s | FileCheck %s -check-prefix=ASAN

typedef __typeof__(sizeof(0)) size_t;
namespace std {
struct nothrow_t {};
std::nothrow_t nothrow;
}
void *operator new[](size_t, const std::nothrow_t &) throw();
void *operator new[](size_t, char *);

struct C {
int x;
~C();
};

C *CallNew() {
return new C[10];
}
// PLAIN-LABEL: CallNew
// PLAIN-NOT: nosanitize
// PLAIN-NOT: __asan_poison_cxx_array_cookie
// ASAN-LABEL: CallNew
// ASAN: store{{.*}}nosanitize
// ASAN-NOT: nosanitize
// ASAN: call void @__asan_poison_cxx_array_cookie

C *CallNewNoThrow() {
return new (std::nothrow) C[10];
}
// PLAIN-LABEL: CallNewNoThrow
// PLAIN-NOT: nosanitize
// PLAIN-NOT: __asan_poison_cxx_array_cookie
// ASAN-LABEL: CallNewNoThrow
// ASAN: store{{.*}}nosanitize
// ASAN-NOT: nosanitize
// ASAN: call void @__asan_poison_cxx_array_cookie

void CallDelete(C *c) {
delete [] c;
}

// PLAIN-LABEL: CallDelete
// PLAIN-NOT: nosanitize
// ASAN-LABEL: CallDelete
// ASAN: load{{.*}}!nosanitize
// ASAN-NOT: nosanitize

char Buffer[20];
C *CallPlacementNew() {
return new (Buffer) C[20];
}
// ASAN-LABEL: CallPlacementNew
// ASAN-NOT: __asan_poison_cxx_array_cookie

0 comments on commit 4ee6904

Please sign in to comment.