]> granicus.if.org Git - clang/commitdiff
[clang/asan] call __asan_poison_cxx_array_cookie after operator new[]
authorKostya Serebryany <kcc@google.com>
Tue, 26 Aug 2014 02:29:59 +0000 (02:29 +0000)
committerKostya Serebryany <kcc@google.com>
Tue, 26 Aug 2014 02:29:59 +0000 (02:29 +0000)
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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@216434 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CodeGenFunction.cpp
lib/CodeGen/ItaniumCXXABI.cpp
lib/CodeGen/SanitizerMetadata.cpp
lib/CodeGen/SanitizerMetadata.h
test/CodeGen/address-sanitizer-and-array-cookie.cpp [new file with mode: 0644]

index 16e20b1fa77f8080e715019b17643f10995c5f53..d18cbc9afb0c99f7355bbdc3cf71e1aff59755b7 100644 (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>
index 5fd0499f67b7c8faaf09e4e242bc0f3687c90a80..5df3e43f4887b93d9e2ac1265a16416b2493ba5e 100644 (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) {
index dd8c133621595db664d9020d4e4ea16d042e6a60..2a2b0ed941968c3ff91e084a46d2f1b5d109925e 100644 (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())
index 9630668e22d88dcd92e7dfa9e42bc5b14c315aa6..4d63aef552f97f61ad2b89cb358f1cc6d3fb5859 100644 (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);
 };
diff --git a/test/CodeGen/address-sanitizer-and-array-cookie.cpp b/test/CodeGen/address-sanitizer-and-array-cookie.cpp
new file mode 100644 (file)
index 0000000..c5882f8
--- /dev/null
@@ -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