From 4ee6904288f1fde659fa00952ec0778bcca5e2b4 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Tue, 26 Aug 2014 02:29:59 +0000 Subject: [PATCH] [clang/asan] call __asan_poison_cxx_array_cookie after operator new[] 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 --- clang/lib/CodeGen/CodeGenFunction.cpp | 7 +-- clang/lib/CodeGen/ItaniumCXXABI.cpp | 22 ++++++-- clang/lib/CodeGen/SanitizerMetadata.cpp | 6 +++ clang/lib/CodeGen/SanitizerMetadata.h | 2 + .../address-sanitizer-and-array-cookie.cpp | 54 +++++++++++++++++++ 5 files changed, 81 insertions(+), 10 deletions(-) create mode 100644 clang/test/CodeGen/address-sanitizer-and-array-cookie.cpp diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 16e20b1fa77f..d18cbc9afb0c 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -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())); - } + if (IsSanitizerScope) + CGM.getSanitizerMetadata()->disableSanitizerForInstruction(I); } template diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 5fd0499f67b7..5df3e43f4887 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -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. @@ -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) { diff --git a/clang/lib/CodeGen/SanitizerMetadata.cpp b/clang/lib/CodeGen/SanitizerMetadata.cpp index dd8c13362159..2a2b0ed94196 100644 --- a/clang/lib/CodeGen/SanitizerMetadata.cpp +++ b/clang/lib/CodeGen/SanitizerMetadata.cpp @@ -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::MDNode *SanitizerMetadata::getLocationMetadata(SourceLocation Loc) { PresumedLoc PLoc = CGM.getContext().getSourceManager().getPresumedLoc(Loc); if (!PLoc.isValid()) diff --git a/clang/lib/CodeGen/SanitizerMetadata.h b/clang/lib/CodeGen/SanitizerMetadata.h index 9630668e22d8..4d63aef552f9 100644 --- a/clang/lib/CodeGen/SanitizerMetadata.h +++ b/clang/lib/CodeGen/SanitizerMetadata.h @@ -18,6 +18,7 @@ namespace llvm { class GlobalVariable; +class Instruction; class MDNode; } @@ -41,6 +42,7 @@ public: StringRef Name, bool IsDynInit = false, bool IsBlacklisted = false); void disableSanitizerForGlobal(llvm::GlobalVariable *GV); + void disableSanitizerForInstruction(llvm::Instruction *I); private: llvm::MDNode *getLocationMetadata(SourceLocation Loc); }; diff --git a/clang/test/CodeGen/address-sanitizer-and-array-cookie.cpp b/clang/test/CodeGen/address-sanitizer-and-array-cookie.cpp new file mode 100644 index 000000000000..c5882f807bc5 --- /dev/null +++ b/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