[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
This commit is contained in:
Kostya Serebryany 2014-08-26 02:29:59 +00:00
parent b06f77b608
commit 4ee6904288
5 changed files with 81 additions and 10 deletions

View File

@ -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>

View File

@ -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) {

View File

@ -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())

View File

@ -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);
};

View File

@ -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