[asan] make sure that the crash callbacks do not get merged (Chandler's idea: insert...
authorKostya Serebryany <kcc@google.com>
Fri, 20 Jul 2012 09:54:50 +0000 (09:54 +0000)
committerKostya Serebryany <kcc@google.com>
Fri, 20 Jul 2012 09:54:50 +0000 (09:54 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@160544 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Transforms/Instrumentation/AddressSanitizer.cpp
test/Instrumentation/AddressSanitizer/basic.ll

index 14348b9bac670b7c1e6f0c87432e410609c643a7..336802668ca5d4d42c897a8ba3b4734f7377fc87 100644 (file)
@@ -18,6 +18,7 @@
 #include "FunctionBlackList.h"
 #include "llvm/Function.h"
 #include "llvm/IRBuilder.h"
+#include "llvm/InlineAsm.h"
 #include "llvm/IntrinsicInst.h"
 #include "llvm/LLVMContext.h"
 #include "llvm/Module.h"
@@ -224,6 +225,7 @@ struct AddressSanitizer : public ModulePass {
   OwningPtr<FunctionBlackList> BL;
   // This array is indexed by AccessIsWrite and log2(AccessSize).
   Function *AsanErrorCallback[2][kNumberOfAccessSizes];
+  InlineAsm *EmptyAsm;
 };
 
 }  // namespace
@@ -276,7 +278,7 @@ static BranchInst *splitBlockAndInsertIfThen(Value *Cmp,
   BranchInst *CheckTerm = 0;
   if (!ThenBlock) {
     LLVMContext &C = Head->getParent()->getParent()->getContext();
-    ThenBlock = BasicBlock::Create(C, "", Head->getParent());
+    ThenBlock = BasicBlock::Create(C, "", Head->getParent(), Tail);
     CheckTerm = BranchInst::Create(Tail, ThenBlock);
   }
   BranchInst *HeadNewTerm =
@@ -414,7 +416,10 @@ Instruction *AddressSanitizer::generateCrashCode(
                            Addr, PC);
   else
     Call = IRB.CreateCall(AsanErrorCallback[IsWrite][AccessSizeIndex], Addr);
-  Call->setDoesNotReturn();
+  // We don't do Call->setDoesNotReturn() because the BB already has
+  // UnreachableInst at the end.
+  // This EmptyAsm is required to avoid callback merge.
+  IRB.CreateCall(EmptyAsm);
   return Call;
 }
 
@@ -483,10 +488,13 @@ void AddressSanitizer::instrumentAddress(AsanFunctionContext &AFC,
 
   size_t Granularity = 1 << MappingScale;
   if (TypeSize < 8 * Granularity) {
-    Instruction *CheckTerm = splitBlockAndInsertIfThen(Cmp);
+    BranchInst *CheckTerm = splitBlockAndInsertIfThen(Cmp);
+    assert(CheckTerm->isUnconditional());
+    BasicBlock *NextBB = CheckTerm->getSuccessor(0);
     IRB.SetInsertPoint(CheckTerm);
     Value *Cmp2 = createSlowPathCmp(IRB, AddrLong, ShadowValue, TypeSize);
-    splitBlockAndInsertIfThen(Cmp2, CrashBlock);
+    BranchInst *NewTerm = BranchInst::Create(CrashBlock, NextBB, Cmp2);
+    ReplaceInstWithInst(CheckTerm, NewTerm);
   } else {
     splitBlockAndInsertIfThen(Cmp, CrashBlock);
   }
@@ -695,6 +703,10 @@ bool AddressSanitizer::runOnModule(Module &M) {
           M.getOrInsertFunction(FunctionName, IRB.getVoidTy(), IntptrTy, NULL));
     }
   }
+  // We insert an empty inline asm after __asan_report* to avoid callback merge.
+  EmptyAsm = InlineAsm::get(FunctionType::get(IRB.getVoidTy(), false),
+                            StringRef(""), StringRef(""),
+                            /*hasSideEffects=*/true);
 
   llvm::Triple targetTriple(M.getTargetTriple());
   bool isAndroid = targetTriple.getEnvironment() == llvm::Triple::ANDROIDEABI;
index 183cddcb5ca772b96a463fedcfd99dcb01036d3f..294ca8ab7560aab680d67882bc873f2bda9a236f 100644 (file)
@@ -16,15 +16,6 @@ define i32 @test_load(i32* %a) address_safety {
 ; CHECK:   icmp ne i8
 ; CHECK:   br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
 ;
-; The actual load comes next because ASan adds the last instrumentation block
-; to the end of the function.
-; CHECK:   %tmp1 = load i32* %a
-; CHECK:   ret i32 %tmp1
-
-; The crash block reports the error.
-; CHECK:   call void @__asan_report_load4(i64 %[[LOAD_ADDR]]) noreturn
-; CHECK:   unreachable
-;
 ; First instrumentation block refines the shadow test.
 ; CHECK:   and i64 %[[LOAD_ADDR]], 7
 ; CHECK:   add i64 %{{.*}}, 3
@@ -32,6 +23,16 @@ define i32 @test_load(i32* %a) address_safety {
 ; CHECK:   icmp sge i8 %{{.*}}, %[[LOAD_SHADOW]]
 ; CHECK:   br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
 ;
+; The actual load comes next because ASan adds the crash block
+; to the end of the function.
+; CHECK:   %tmp1 = load i32* %a
+; CHECK:   ret i32 %tmp1
+
+; The crash block reports the error.
+; CHECK:   call void @__asan_report_load4(i64 %[[LOAD_ADDR]])
+; CHECK:   unreachable
+;
+
 
 entry:
   %tmp1 = load i32* %a
@@ -49,15 +50,6 @@ define void @test_store(i32* %a) address_safety {
 ; CHECK:   icmp ne i8
 ; CHECK:   br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
 ;
-; The actual store comes next because ASan adds the last instrumentation block
-; to the end of the function.
-; CHECK:   store i32 42, i32* %a
-; CHECK:   ret void
-;
-; The crash block reports the error.
-; CHECK:   call void @__asan_report_store4(i64 %[[STORE_ADDR]]) noreturn
-; CHECK:   unreachable
-;
 ; First instrumentation block refines the shadow test.
 ; CHECK:   and i64 %[[STORE_ADDR]], 7
 ; CHECK:   add i64 %{{.*}}, 3
@@ -65,6 +57,15 @@ define void @test_store(i32* %a) address_safety {
 ; CHECK:   icmp sge i8 %{{.*}}, %[[STORE_SHADOW]]
 ; CHECK:   br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
 ;
+; The actual load comes next because ASan adds the crash block
+; to the end of the function.
+; CHECK:   store i32 42, i32* %a
+; CHECK:   ret void
+;
+; The crash block reports the error.
+; CHECK:   call void @__asan_report_store4(i64 %[[STORE_ADDR]])
+; CHECK:   unreachable
+;
 
 entry:
   store i32 42, i32* %a