Revert r160602.
[oota-llvm.git] / lib / Transforms / Instrumentation / AddressSanitizer.cpp
index 1fc1871d7124a7b32082395d09c09ef7a0328dbd..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"
@@ -144,15 +145,24 @@ static cl::opt<int> ClDebugMax("asan-debug-max", cl::desc("Debug man inst"),
 
 namespace {
 
+/// When the crash callbacks are merged, they receive some amount of arguments
+/// that are merged in a PHI node. This struct represents arguments from one
+/// call site.
+struct CrashArg {
+  Value *Arg1;
+  Value *Arg2;
+};
+
 /// An object of this type is created while instrumenting every function.
 struct AsanFunctionContext {
-  AsanFunctionContext() {
-    memset(this, 0, sizeof(*this));
-  }
+  AsanFunctionContext(Function &Function) : F(Function), CrashBlock() { }
 
+  Function &F;
   // These are initially zero. If we require at least one call to
   // __asan_report_{read,write}{1,2,4,8,16}, an appropriate BB is created.
   BasicBlock *CrashBlock[2][kNumberOfAccessSizes];
+  typedef  SmallVector<CrashArg, 8> CrashArgsVec;
+  CrashArgsVec CrashArgs[2][kNumberOfAccessSizes];
 };
 
 /// AddressSanitizer: instrument the code in module to find memory bugs.
@@ -165,8 +175,8 @@ struct AddressSanitizer : public ModulePass {
                          Value *Addr, uint32_t TypeSize, bool IsWrite);
   Value *createSlowPathCmp(IRBuilder<> &IRB, Value *AddrLong,
                            Value *ShadowValue, uint32_t TypeSize);
-  Instruction *generateCrashCode(BasicBlock *BB, Value *Addr,
-                                 bool IsWrite, uint32_t TypeSize);
+  Instruction *generateCrashCode(BasicBlock *BB, Value *Addr, Value *PC,
+                                 bool IsWrite, size_t AccessSizeIndex);
   bool instrumentMemIntrinsic(AsanFunctionContext &AFC, MemIntrinsic *MI);
   void instrumentMemIntrinsicParam(AsanFunctionContext &AFC,
                                    Instruction *OrigIns, Value *Addr,
@@ -215,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
@@ -232,6 +243,12 @@ const char *AddressSanitizer::getPassName() const {
   return "AddressSanitizer";
 }
 
+static size_t TypeSizeToSizeIndex(uint32_t TypeSize) {
+  size_t Res = CountTrailingZeros_32(TypeSize / 8);
+  assert(Res < kNumberOfAccessSizes);
+  return Res;
+}
+
 // Create a constant for Str so that we can pass it to the run-time lib.
 static GlobalVariable *createPrivateGlobalForString(Module &M, StringRef Str) {
   Constant *StrConst = ConstantDataArray::getString(M.getContext(), Str);
@@ -251,17 +268,17 @@ static GlobalVariable *createPrivateGlobalForString(Module &M, StringRef Str) {
 //   Tail
 //
 // If ThenBlock is zero, a new block is created and its terminator is returned.
-// Otherwize NULL is returned.
+// Otherwize 0 is returned.
 static BranchInst *splitBlockAndInsertIfThen(Value *Cmp,
                                              BasicBlock *ThenBlock = 0) {
   Instruction *SplitBefore = cast<Instruction>(Cmp)->getNextNode();
   BasicBlock *Head = SplitBefore->getParent();
   BasicBlock *Tail = Head->splitBasicBlock(SplitBefore);
   TerminatorInst *HeadOldTerm = Head->getTerminator();
-  BranchInst *CheckTerm = NULL;
+  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 =
@@ -306,7 +323,7 @@ bool AddressSanitizer::instrumentMemIntrinsic(AsanFunctionContext &AFC,
                                               MemIntrinsic *MI) {
   Value *Dst = MI->getDest();
   MemTransferInst *MemTran = dyn_cast<MemTransferInst>(MI);
-  Value *Src = MemTran ? MemTran->getSource() : NULL;
+  Value *Src = MemTran ? MemTran->getSource() : 0;
   Value *Length = MI->getLength();
 
   Constant *ConstLength = dyn_cast<Constant>(Length);
@@ -390,17 +407,23 @@ Function *AddressSanitizer::checkInterfaceFunction(Constant *FuncOrBitcast) {
 }
 
 Instruction *AddressSanitizer::generateCrashCode(
-    BasicBlock *BB, Value *Addr, bool IsWrite, uint32_t TypeSize) {
+    BasicBlock *BB, Value *Addr, Value *PC,
+    bool IsWrite, size_t AccessSizeIndex) {
   IRBuilder<> IRB(BB->getFirstNonPHI());
-  size_t AccessSizeIndex = CountTrailingZeros_32(TypeSize / 8);
-  assert(AccessSizeIndex < kNumberOfAccessSizes);
-  CallInst *Call = IRB.CreateCall(AsanErrorCallback[IsWrite][AccessSizeIndex],
-                                  Addr);
-  Call->setDoesNotReturn();
+  CallInst *Call;
+  if (PC)
+    Call = IRB.CreateCall2(AsanErrorCallback[IsWrite][AccessSizeIndex],
+                           Addr, PC);
+  else
+    Call = IRB.CreateCall(AsanErrorCallback[IsWrite][AccessSizeIndex], Addr);
+  // 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;
 }
 
-Value * AddressSanitizer::createSlowPathCmp(IRBuilder<> &IRB, Value *AddrLong,
+Value *AddressSanitizer::createSlowPathCmp(IRBuilder<> &IRB, Value *AddrLong,
                                             Value *ShadowValue,
                                             uint32_t TypeSize) {
   size_t Granularity = 1 << MappingScale;
@@ -434,24 +457,44 @@ void AddressSanitizer::instrumentAddress(AsanFunctionContext &AFC,
 
   Value *Cmp = IRB.CreateICmpNE(ShadowValue, CmpVal);
 
-  BasicBlock *CrashBlock = NULL;
+  BasicBlock *CrashBlock = 0;
   if (ClMergeCallbacks) {
-    llvm_unreachable("unimplemented yet");
+    size_t AccessSizeIndex = TypeSizeToSizeIndex(TypeSize);
+    BasicBlock **Cached = &AFC.CrashBlock[IsWrite][AccessSizeIndex];
+    if (!*Cached) {
+      std::string BBName("crash_bb-");
+      BBName += (IsWrite ? "w-" : "r-") + itostr(1 << AccessSizeIndex);
+      BasicBlock *BB = BasicBlock::Create(*C, BBName, &AFC.F);
+      new UnreachableInst(*C, BB);
+      *Cached = BB;
+    }
+    CrashBlock = *Cached;
+    // We need to pass the PC as the second parameter to __asan_report_*.
+    // There are few problems:
+    //  - Some architectures (e.g. x86_32) don't have a cheap way to get the PC.
+    //  - LLVM doesn't have the appropriate intrinsic.
+    // For now, put a random number into the PC, just to allow experiments.
+    Value *PC = ConstantInt::get(IntptrTy, rand());
+    CrashArg Arg = {AddrLong, PC};
+    AFC.CrashArgs[IsWrite][AccessSizeIndex].push_back(Arg);
   } else {
-    CrashBlock = BasicBlock::Create(*C, "crash_bb",
-                                    OrigIns->getParent()->getParent());
+    CrashBlock = BasicBlock::Create(*C, "crash_bb", &AFC.F);
     new UnreachableInst(*C, CrashBlock);
+    size_t AccessSizeIndex = TypeSizeToSizeIndex(TypeSize);
     Instruction *Crash =
-        generateCrashCode(CrashBlock, AddrLong, IsWrite, TypeSize);
+        generateCrashCode(CrashBlock, AddrLong, 0, IsWrite, AccessSizeIndex);
     Crash->setDebugLoc(OrigIns->getDebugLoc());
   }
 
   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);
   }
@@ -650,10 +693,20 @@ bool AddressSanitizer::runOnModule(Module &M) {
       // IsWrite and TypeSize are encoded in the function name.
       std::string FunctionName = std::string(kAsanReportErrorTemplate) +
           (AccessIsWrite ? "store" : "load") + itostr(1 << AccessSizeIndex);
-      AsanErrorCallback[AccessIsWrite][AccessSizeIndex] = cast<Function>(
-        M.getOrInsertFunction(FunctionName, IRB.getVoidTy(), IntptrTy, NULL));
+      // If we are merging crash callbacks, they have two parameters.
+      if (ClMergeCallbacks)
+        AsanErrorCallback[AccessIsWrite][AccessSizeIndex] = cast<Function>(
+          M.getOrInsertFunction(FunctionName, IRB.getVoidTy(), IntptrTy,
+                                IntptrTy, NULL));
+      else
+        AsanErrorCallback[AccessIsWrite][AccessSizeIndex] = cast<Function>(
+          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;
@@ -776,7 +829,7 @@ bool AddressSanitizer::handleFunction(Module &M, Function &F) {
     }
   }
 
-  AsanFunctionContext AFC;
+  AsanFunctionContext AFC(F);
 
   // Instrument.
   int NumInstrumented = 0;
@@ -792,6 +845,33 @@ bool AddressSanitizer::handleFunction(Module &M, Function &F) {
     NumInstrumented++;
   }
 
+  // Create PHI nodes and crash callbacks if we are merging crash callbacks.
+  if (NumInstrumented) {
+    for (size_t IsWrite = 0; IsWrite <= 1; IsWrite++) {
+      for (size_t AccessSizeIndex = 0; AccessSizeIndex < kNumberOfAccessSizes;
+           AccessSizeIndex++) {
+        BasicBlock *BB = AFC.CrashBlock[IsWrite][AccessSizeIndex];
+        if (!BB) continue;
+        assert(ClMergeCallbacks);
+        AsanFunctionContext::CrashArgsVec &Args =
+            AFC.CrashArgs[IsWrite][AccessSizeIndex];
+        IRBuilder<> IRB(BB->getFirstNonPHI());
+        size_t n = Args.size();
+        PHINode *PN1 = IRB.CreatePHI(IntptrTy, n);
+        PHINode *PN2 = IRB.CreatePHI(IntptrTy, n);
+        // We need to match crash parameters and the predecessors.
+        for (pred_iterator PI = pred_begin(BB), PE = pred_end(BB);
+             PI != PE; ++PI) {
+          n--;
+          PN1->addIncoming(Args[n].Arg1, *PI);
+          PN2->addIncoming(Args[n].Arg2, *PI);
+        }
+        assert(n == 0);
+        generateCrashCode(BB, PN1, PN2, IsWrite, AccessSizeIndex);
+      }
+    }
+  }
+
   DEBUG(dbgs() << F);
 
   bool ChangedStack = poisonStackInFunction(M, F);