Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(572)

Unified Diff: lib/Transforms/Instrumentation/AddressSanitizer.cpp

Issue 4842041: AddressSanitizer: first commit of the instrumentation pass Base URL: http://llvm.org/svn/llvm-project/llvm/trunk/
Patch Set: typo Created 13 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « include/llvm/Transforms/Instrumentation.h ('k') | lib/Transforms/Instrumentation/CMakeLists.txt » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/Transforms/Instrumentation/AddressSanitizer.cpp
===================================================================
--- lib/Transforms/Instrumentation/AddressSanitizer.cpp (revision 0)
+++ lib/Transforms/Instrumentation/AddressSanitizer.cpp (revision 0)
@@ -0,0 +1,643 @@
+//===-- AddressSanitizer.cpp - memory error detector ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+// Details of the algorithm:
+// http://code.google.com/p/address-sanitizer/wiki/AddressSanitizerAlgorithm
+//
+// Short version:
+// A part of the virtual address space is dedicated to the 'shadow memory'.
+// The mapping between the application memory and shadow memory looks like
+// Shadow = (Mem >> Scale) + Offset
+// The typical (default) value of Scale is 3.
+// Typical values of Offset: 2^29 on 32-bit systems and 2^44 on 64-bit systems.
+//
+// Every byte of the shadow memory corresponds to 2^Scale aligned bytes of the
+// application memory and describes whether the given memory is addressable.
+// Every aligned group of 2^Scale bytes may be only in (2^Scale)+1 states:
+// first 'k' bytes are addressable, the rest (2^Scale)-k are not.
+//
+// The goal of the instrumentation pass (this file) is to instrument every
+// memory access (read or write) in the following way:
+// Before:
+// *mem = ... (or ... = *mem)
+// After:
+// ReadShadowAndCheckIfAddressable(mem);
+// *mem = ...
+//
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "asan"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Analysis/DebugInfo.h"
+#include "llvm/CallingConv.h"
+#include "llvm/DerivedTypes.h"
+#include "llvm/Function.h"
+#include "llvm/GlobalAlias.h"
+#include "llvm/InlineAsm.h"
+#include "llvm/InstrTypes.h"
+#include "llvm/IntrinsicInst.h"
+#include "llvm/LLVMContext.h"
+#include "llvm/Module.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/IRBuilder.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Regex.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/system_error.h"
+#include "llvm/Target/TargetData.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Transforms/Instrumentation.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Type.h"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string>
+#include <vector>
+#include <algorithm>
+
+// TODO(kcc): instrument stack objects.
+// TODO(kcc): create redzones for globals.
+// TODO(kcc): implement black list for function names.
+
+using std::vector;
+using std::max;
+
+using namespace llvm;
+
+static const uint64_t kDefaultShadowScale = 3;
+static const uint64_t kDefaultShadowOffset32 = 29;
+static const uint64_t kDefaultShadowOffset64 = 44;
+
+// Command-line flags.
+
+// (potentially) user-visible flags.
+static cl::opt<bool> ClAsan("asan",
+ cl::desc("enable AddressSanitizer"), cl::init(false));
+static cl::opt<bool> ClInstrumentReads("asan-instrument-reads",
+ cl::desc("instrument read instructions"), cl::init(true));
+static cl::opt<bool> ClInstrumentWrites("asan-instrument-writes",
+ cl::desc("instrument write instructions"), cl::init(true));
+static cl::opt<bool> ClMemIntrin("asan-memintrin",
+ cl::desc("Handle memset/memcpy/memmove"), cl::init(true));
+static cl::opt<bool> ClUseCall("asan-use-call",
+ cl::desc("Use function call to generate a crash"), cl::init(false));
+static cl::opt<bool> ClUseBTS("asan-use-bts",
+ cl::desc("Use the BTS instruction (x86)"), cl::init(false));
+
+// These flags are mostly for testing/benchmarking the tool itself.
+// The mapping looks like
+// Shadow = (Mem >> Scale) + (1 << OffsetLog)
+static cl::opt<int> ClMappingScale("asan-mapping-scale",
+ cl::desc("scale of asan shadow mapping"), cl::init(0));
+static cl::opt<int> ClMappingOffsetLog("asan-mapping-offset-log",
+ cl::desc("offset of asan shadow mapping"), cl::init(0));
+
+// Optimization flags. Not user visible, used mostly for testing
+// and benchmarking the tool.
+static cl::opt<bool> ClOpt("asan-opt",
+ cl::desc("Optimize instrumentation"), cl::init(true));
+static cl::opt<bool> ClOptSameTemp("asan-opt-same-temp",
+ cl::desc("Instrument the same temp just once"), cl::init(true));
+static cl::opt<bool> ClOptGlobals("asan-opt-globals",
+ cl::desc("Don't instrument scalar globals"), cl::init(true));
+
+// Debug flags.
+static cl::opt<int> ClDebug("asan-debug", cl::desc("debug"), cl::init(0));
+static cl::opt<std::string> ClDebugFunc("asan-debug-func",
+ cl::desc("Debug func"));
+static cl::opt<int> ClDebugMin("asan-debug-min",
+ cl::desc("Debug min inst"), cl::init(-1));
+static cl::opt<int> ClDebugMax("asan-debug-max",
+ cl::desc("Debug max inst"), cl::init(-1));
+namespace {
+
+// Call to this function is inserted into every module's llvm.global_ctors.
+static const char *kAsanModuleCtorName = "asan.module_ctor";
+
+struct AddressSanitizer : public ModulePass {
+ AddressSanitizer();
+ void instrumentMop(BasicBlock::iterator &BI);
+ void instrumentAddress(Instruction *orig_mop, IRBuilder<> &irb,
+ Value *Addr, size_t type_size, bool is_w);
+ Instruction *generateCrashCode(IRBuilder<> &irb, Value *Addr,
+ int telltale_value);
+ bool instrumentMemIntrinsic(MemIntrinsic *mem_intr);
+ void instrumentMemIntrinsicParam(Instruction *orig_mop, Value *addr,
+ Value *size,
+ Instruction *insert_before, bool is_w);
+ Value *memToShadow(Value *Shadow, IRBuilder<> &irb);
+ bool handleFunction(Function &F);
+ virtual bool runOnModule(Module &M);
+ void appendToGlobalCtors(Module &M, Function *f);
+ BranchInst *splitBlockAndInsertIfThen(Instruction *SplitBefore, Value *cmp);
+ static char ID; // Pass identification, replacement for typeid
+
+ private:
+ Module *CurrentModule;
+ LLVMContext *C;
+ TargetData *TD;
+ uint64_t MappingOffsetLog;
+ int MappingScale;
+ int LongSize;
+ Type *VoidTy;
+ Type *LongTy;
+ Type *LongPtrTy;
+ Type *i32Ty;
+ Type *i32PtrTy;
+ Type *ByteTy;
+ Type *BytePtrTy;
+ FunctionType *Fn0Ty;
+};
+
+} // namespace
+
+char AddressSanitizer::ID = 0;
+INITIALIZE_PASS(AddressSanitizer, "asan",
+ "AddressSanitizer: detects use-after-free and out-of-bounds bugs.",
+ false, false)
+AddressSanitizer::AddressSanitizer() : ModulePass(ID) { }
+ModulePass *llvm::createAddressSanitizerPass() {
+ return new AddressSanitizer();
+}
+
+// Split the basic block and insert an if-then code.
+// Before:
+// Head
+// SplitBefore
+// Tail
+// After:
+// Head
+// if (Cmp)
+// NewBasicBlock
+// SplitBefore
+// Tail
+//
+// Returns the NewBasicBlock's terminator.
+BranchInst *AddressSanitizer::splitBlockAndInsertIfThen(
+ Instruction *SplitBefore, Value *Cmp) {
+ BasicBlock *Head = SplitBefore->getParent();
+ BasicBlock *Tail = Head->splitBasicBlock(SplitBefore);
+ TerminatorInst *HeadOldTerm = Head->getTerminator();
+ BasicBlock *NewBasicBlock =
+ BasicBlock::Create(*C, "", Head->getParent());
+ BranchInst *HeadNewTerm = BranchInst::Create(/*ifTrue*/NewBasicBlock,
+ /*ifFalse*/Tail,
+ Cmp);
+ ReplaceInstWithInst(HeadOldTerm, HeadNewTerm);
+
+ BranchInst *CheckTerm = BranchInst::Create(Tail, NewBasicBlock);
+ return CheckTerm;
+}
+
+static void CloneDebugInfo(Instruction *from, Instruction *to) {
+ MDNode *dbg = from->getMetadata(LLVMContext::MD_dbg);
+ if (dbg)
+ to->setMetadata("dbg", dbg);
+}
+
+Value *AddressSanitizer::memToShadow(Value *Shadow, IRBuilder<> &irb) {
+ // Shadow >> scale
+ Shadow = irb.CreateLShr(Shadow, MappingScale);
+ if (ClUseBTS) {
+ // Generate something like "bts $0x2c,%rcx". This is more compact than
+ // "mov $0x100000000000,%rdx; or %rdx,%rcx", but slower.
+ char bts[30];
+ sprintf(bts, "bts $$%ld, $0", (long)MappingOffsetLog);
+ Value *insn = InlineAsm::get(
+ FunctionType::get(LongTy, ArrayRef<Type*>(LongTy), false),
+ StringRef(bts), StringRef("=r,0"), true);
+ Value *res = irb.CreateCall(insn, Shadow);
+ return res;
+ }
+ // (Shadow >> scale) | offset
+ return irb.CreateOr(Shadow, ConstantInt::get(LongTy,
+ 1ULL << MappingOffsetLog));
+}
+
+void AddressSanitizer::instrumentMemIntrinsicParam(Instruction *orig_mop,
+ Value *addr, Value *size, Instruction *insert_before, bool is_w) {
+ // Check the first byte.
+ {
+ IRBuilder<> irb(insert_before->getParent(), insert_before);
+ instrumentAddress(orig_mop, irb, addr, 8, is_w);
+ }
+ // Check the last byte.
+ {
+ IRBuilder<> irb(insert_before->getParent(), insert_before);
+ Value *size_minus_one = irb.CreateSub(
+ size, ConstantInt::get(size->getType(), 1));
+ size_minus_one = irb.CreateIntCast(size_minus_one, LongTy, false);
+ Value *addr_long = irb.CreatePointerCast(addr, LongTy);
+ Value *addr_plus_size_minus_one = irb.CreateAdd(addr_long, size_minus_one);
+ instrumentAddress(orig_mop, irb, addr_plus_size_minus_one, 8, is_w);
+ }
+}
+
+// Instrument memset/memmove/memcpy
+bool AddressSanitizer::instrumentMemIntrinsic(MemIntrinsic *mem_intr) {
+ Value *dst = mem_intr->getDest();
+ MemTransferInst *mtran = dyn_cast<MemTransferInst>(mem_intr);
+ Value *src = mtran ? mtran->getSource() : NULL;
+ Value *length = mem_intr->getLength();
+
+ Constant *const_length = dyn_cast<Constant>(length);
+ Instruction *insert_before = mem_intr->getNextNode();
+ if (const_length) {
+ if (const_length->isNullValue()) return false;
+ } else {
+ // The size is not a constant so it could be zero -- check at run-time.
+ IRBuilder<> irb(insert_before->getParent(), insert_before);
+
+ Value *cmp = irb.CreateICmpNE(length,
+ Constant::getNullValue(length->getType()));
+ BranchInst *term = splitBlockAndInsertIfThen(insert_before, cmp);
+ insert_before = term;
+ }
+
+ instrumentMemIntrinsicParam(mem_intr, dst, length, insert_before, true);
+ if (src)
+ instrumentMemIntrinsicParam(mem_intr, src, length, insert_before, false);
+ return true;
+}
+
+static Value *getLDSTOperand(Instruction *inst) {
+ if (LoadInst *ld = dyn_cast<LoadInst>(inst)) {
+ return ld->getPointerOperand();
+ }
+ return cast<StoreInst>(*inst).getPointerOperand();
+}
+
+void AddressSanitizer::instrumentMop(BasicBlock::iterator &BI) {
+ Instruction *mop = BI;
+ int is_w = !!isa<StoreInst>(*mop);
+ Value *Addr = getLDSTOperand(mop);
+ if (ClOpt && ClOptGlobals && isa<GlobalVariable>(Addr)) {
+ // We are accessing a global scalar variable. Nothing to catch here.
+ return;
+ }
+ Type *OrigPtrTy = Addr->getType();
+ Type *OrigTy = cast<PointerType>(OrigPtrTy)->getElementType();
+
+ assert(OrigTy->isSized());
+ unsigned type_size = TD->getTypeStoreSizeInBits(OrigTy);
+
+ if (type_size != 8 && type_size != 16
+ && type_size != 32 && type_size != 64 && type_size != 128) {
+ // TODO(kcc): do something better.
+ return;
+ }
+
+ IRBuilder<> irb1(BI->getParent(), BI);
+ instrumentAddress(mop, irb1, Addr, type_size, is_w);
+}
+
+Instruction *AddressSanitizer::generateCrashCode(
+ IRBuilder<> &irb, Value *Addr, int telltale_value) {
+ if (ClUseCall) {
+ // Here we use a call instead of arch-specific asm to report an error.
+ // This is almost always slower (because the codegen needs to generate
+ // prologue/epilogue for otherwise leaf functions) and generates more code.
+ // This mode could be useful if we can not use SIGILL for some reason.
+ //
+ // The telltale_value (is_write and size) is encoded in the function name.
+ char function_name[100];
+ sprintf(function_name, "__asan_report_error_%d", telltale_value);
+ Value *asan_report_warning = CurrentModule->getOrInsertFunction(
+ function_name, VoidTy, LongTy, NULL);
+ CallInst *call = irb.CreateCall(asan_report_warning, Addr);
+ return call;
+ }
+
+ // This code is x86-specific.
+ // Move the failing address to %rax/%eax
+ FunctionType *Fn1Ty = FunctionType::get(
+ VoidTy, ArrayRef<Type*>(LongTy), false);
+ const char *mov_str = LongSize == 32
+ ? "mov $0, %eax" : "mov $0, %rax";
+ Value *asm_mov = InlineAsm::get(
+ Fn1Ty, StringRef(mov_str), StringRef("r"), true);
+ irb.CreateCall(asm_mov, Addr);
+
+ // crash with ud2; could use int3, but it is less friendly to gdb.
+ // after ud2 put a 1-byte instruction that encodes the access type and size.
+
+ const char *telltale_insns[16] = {
+ "push %eax", // 0x50
+ "push %ecx", // 0x51
+ "push %edx", // 0x52
+ "push %ebx", // 0x53
+ "push %esp", // 0x54
+ "push %ebp", // 0x55
+ "push %esi", // 0x56
+ "push %edi", // 0x57
+ "pop %eax", // 0x58
+ "pop %ecx", // 0x59
+ "pop %edx", // 0x5a
+ "pop %ebx", // 0x5b
+ "pop %esp", // 0x5c
+ "pop %ebp", // 0x5d
+ "pop %esi", // 0x5e
+ "pop %edi" // 0x5f
+ };
+
+ std::string asm_str = "ud2;";
+ asm_str += telltale_insns[telltale_value];
+ Value *my_asm = InlineAsm::get(Fn0Ty, StringRef(asm_str),
+ StringRef(""), true);
+ CallInst *asm_call = irb.CreateCall(my_asm);
+
+ // This saves us one jump, but triggers a bug in RA (or somewhere else):
+ // while building 483.xalancbmk the compiler goes into infinite loop in
+ // llvm::SpillPlacement::iterate() / RAGreedy::growRegion
+ // asm_call->setDoesNotReturn();
+ return asm_call;
+}
+
+void AddressSanitizer::instrumentAddress(Instruction *orig_mop,
+ IRBuilder<> &irb1, Value *Addr,
+ size_t type_size, bool is_w) {
+ unsigned log_of_size_in_bytes = __builtin_ctz(type_size / 8);
+ assert(8U * (1 << log_of_size_in_bytes) == type_size);
+ uint8_t telltale_value = is_w * 8 + log_of_size_in_bytes;
+ assert(telltale_value < 16);
+
+ Value *AddrLong = irb1.CreatePointerCast(Addr, LongTy);
+
+ Type *ShadowTy = IntegerType::get(
+ *C, max((size_t)8, type_size >> MappingScale));
+ Type *ShadowPtrTy = PointerType::get(ShadowTy, 0);
+ Value *ShadowPtr = memToShadow(AddrLong, irb1);
+ Value *CmpVal = Constant::getNullValue(ShadowTy);
+ Value *ShadowValue = irb1.CreateLoad(
+ irb1.CreateIntToPtr(ShadowPtr, ShadowPtrTy));
+
+ Value *Cmp = irb1.CreateICmpNE(ShadowValue, CmpVal);
+
+ Instruction *CheckTerm = splitBlockAndInsertIfThen(
+ cast<Instruction>(Cmp)->getNextNode(), Cmp);
+ IRBuilder<> irb2(CheckTerm->getParent(), CheckTerm);
+
+ size_t granularity = 1 << MappingScale;
+ if (type_size < 8 * granularity) {
+ // addr & (granularity - 1)
+ Value *Lower3Bits = irb2.CreateAnd(
+ AddrLong, ConstantInt::get(LongTy, granularity - 1));
+ // (addr & (granularity - 1)) + size - 1
+ Value *LastAccessedByte = irb2.CreateAdd(
+ Lower3Bits, ConstantInt::get(LongTy, type_size / 8 - 1));
+ // (uint8_t) ((addr & (granularity-1)) + size - 1)
+ LastAccessedByte = irb2.CreateIntCast(
+ LastAccessedByte, ByteTy, false);
+ // ((uint8_t) ((addr & (granularity-1)) + size - 1)) >= ShadowValue
+ Value *cmp2 = irb2.CreateICmpSGE(LastAccessedByte, ShadowValue);
+
+ CheckTerm = splitBlockAndInsertIfThen(CheckTerm, cmp2);
+ }
+
+ IRBuilder<> irb3(CheckTerm->getParent(), CheckTerm);
+ Instruction *crash = generateCrashCode(irb3, AddrLong, telltale_value);
+ CloneDebugInfo(orig_mop, crash);
+}
+
+// Append 'f' to the list of global ctors. The asan.module_ctor should be called
+// before anything else, so we insert the function call twice,
+// in the beginning and at the end of the list.
+// The code is shamelessly stolen from
+// RegisterRuntimeInitializer::insertInitializerIntoGlobalCtorList().
+// LLVM may need a general API function for this.
+void AddressSanitizer::appendToGlobalCtors(Module &M, Function *f) {
+
+ FunctionType *FnTy = FunctionType::get(VoidTy, false);
+ StructType *ty = StructType::get(
+ i32Ty, PointerType::getUnqual(FnTy), NULL);
+
+ Constant *RuntimeCtorInit = ConstantStruct::get(
+ ty, ConstantInt::get (i32Ty, 65535), f, NULL);
+
+ // Get the current set of static global constructors and add the new ctor
+ // to the list.
+ std::vector<Constant *> CurrentCtors;
+ GlobalVariable * GVCtor = M.getNamedGlobal ("llvm.global_ctors");
+ if (GVCtor) {
+ // insert for the first time.
+ CurrentCtors.push_back(RuntimeCtorInit);
+ if (Constant *Const = GVCtor->getInitializer()) {
+ for (unsigned index = 0; index < Const->getNumOperands(); ++index) {
+ CurrentCtors.push_back (cast<Constant>(Const->getOperand (index)));
+ }
+ }
+ // Rename the global variable so that we can name our global
+ // llvm.global_ctors.
+ GVCtor->setName ("removed");
+ GVCtor->eraseFromParent();
+ }
+
+ // insert for the second time.
+ CurrentCtors.push_back(RuntimeCtorInit);
+
+ // Create a new initializer.
+ ArrayType * AT = ArrayType::get (RuntimeCtorInit->getType(),
+ CurrentCtors.size());
+ Constant *NewInit = ConstantArray::get (AT, CurrentCtors);
+
+ // Create the new llvm.global_ctors global variable and replace all uses of
+ // the old global variable with the new one.
+ new GlobalVariable (M,
+ NewInit->getType(),
+ false,
+ GlobalValue::AppendingLinkage,
+ NewInit,
+ "llvm.global_ctors");
+}
+
+//virtual
+bool AddressSanitizer::runOnModule(Module &M) {
+ if (!ClAsan) return false;
+ // Initialize the private fields. No one has accessed them before.
+ TD = getAnalysisIfAvailable<TargetData>();
+ if (!TD)
+ return false;
+
+ CurrentModule = &M;
+ C = &(M.getContext());
+ LongSize = TD->getPointerSizeInBits();
+ LongTy = Type::getIntNTy(*C, LongSize);
+ i32Ty = Type::getIntNTy(*C, 32);
+ ByteTy = Type::getInt8Ty(*C);
+ BytePtrTy = PointerType::get(ByteTy, 0);
+ LongPtrTy = PointerType::get(LongTy, 0);
+ i32PtrTy = PointerType::get(i32Ty, 0);
+ VoidTy = Type::getVoidTy(*C);
+ Fn0Ty = FunctionType::get(VoidTy, false);
+
+ Function *asan_ctor = Function::Create(
+ Fn0Ty, GlobalValue::InternalLinkage, kAsanModuleCtorName, &M);
+ BasicBlock *asan_ctor_bb = BasicBlock::Create(*C, "", asan_ctor);
+ Instruction *asan_ctor_insert_before = ReturnInst::Create(*C, asan_ctor_bb);
+
+ // call __asan_init in the module ctor.
+ IRBuilder<> irb(asan_ctor_bb, asan_ctor_insert_before);
+ Value *asan_init = M.getOrInsertFunction("__asan_init", VoidTy, NULL);
+ cast<Function>(asan_init)->setLinkage(Function::ExternalLinkage);
+ irb.CreateCall(asan_init);
+
+ MappingOffsetLog = LongSize == 32
+ ? kDefaultShadowOffset32 : kDefaultShadowOffset64;
+ if (ClMappingOffsetLog) {
+ MappingOffsetLog = ClMappingOffsetLog;
+ }
+ MappingScale = kDefaultShadowScale;
+ if (ClMappingScale) {
+ MappingScale = ClMappingScale;
+ }
+ GlobalValue *asan_mapping_offset =
+ new GlobalVariable(M, LongTy, true, GlobalValue::LinkOnceODRLinkage,
+ ConstantInt::get(LongTy, 1ULL << MappingOffsetLog),
+ "__asan_mapping_offset");
+ GlobalValue *asan_mapping_scale =
+ new GlobalVariable(M, LongTy, true, GlobalValue::LinkOnceODRLinkage,
+ ConstantInt::get(LongTy, MappingScale),
+ "__asan_mapping_scale");
+
+ // Read these globals, otherwise they may be optimized away.
+ irb.CreateLoad(asan_mapping_scale, true);
+ irb.CreateLoad(asan_mapping_offset, true);
+
+ bool res = false;
+
+ for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) {
+ if (F->isDeclaration()) continue;
+ res |= handleFunction(*F);
+ }
+
+ appendToGlobalCtors(M, asan_ctor);
+
+ return res;
+}
+
+static bool blockHasException(BasicBlock &bb) {
+ for (BasicBlock::iterator BI = bb.begin(), BE = bb.end();
+ BI != BE; ++BI) {
+ // TODO(kcc):
+ // Workaround for a strange compile assertion while building 483.xalancbmk
+ // If we instrument a basic block which calls llvm.eh.exception
+ // llvm later crashes with this:
+ // lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp:212: void
+ // llvm::FunctionLoweringInfo::clear(): Assertion `CatchInfoFound.size()
+ // == CatchInfoLost.size() && "Not all catch info was assigned to a
+ // landing pad!"' failed.
+ if (isa<CallInst>(BI)) {
+ CallInst *call = cast<CallInst>(BI);
+ Function *func = call->getCalledFunction();
+ if (func && func->getNameStr() == "llvm.eh.exception") {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static bool blockOrItsSuccHasException(BasicBlock &bb) {
+ if (blockHasException(bb)) return true;
+ const TerminatorInst *term = bb.getTerminator();
+ if (term->getNumSuccessors() == 1 &&
+ blockHasException(*term->getSuccessor(0)))
+ return true;
+ return false;
+}
+
+bool AddressSanitizer::handleFunction(Function &F) {
+ if (F.getNameStr() == kAsanModuleCtorName) return false;
+
+ if (!ClDebugFunc.empty() && ClDebugFunc != F.getNameStr())
+ return false;
+ // We want to instrument every address only once per basic block
+ // (unless there are calls between uses).
+ SmallSet<Value*, 16> temps_to_instrument;
+
+ SmallSet<Instruction*, 16> to_instrument;
+
+ // Fill the set of memory operations to instrument.
+ for (Function::iterator FI = F.begin(), FE = F.end();
+ FI != FE; ++FI) {
+ if (blockOrItsSuccHasException(*FI)) continue;
+ temps_to_instrument.clear();
+ for (BasicBlock::iterator BI = FI->begin(), BE = FI->end();
+ BI != BE; ++BI) {
+ if ((isa<LoadInst>(BI) && ClInstrumentReads) ||
+ (isa<StoreInst>(BI) && ClInstrumentWrites)) {
+ Value *addr = getLDSTOperand(BI);
+ if (ClOpt && ClOptSameTemp) {
+ if (!temps_to_instrument.insert(addr))
+ continue; // We've seen this temp in the current BB.
+ }
+ } else if (isa<MemIntrinsic>(BI) && ClMemIntrin) {
+ ; // ok, take it.
+ } else {
+ if (isa<CallInst>(BI)) {
+ // A call inside BB.
+ temps_to_instrument.clear();
+ }
+ continue;
+ }
+ to_instrument.insert(BI);
+ }
+ }
+
+ // Instrument.
+ int n_instrumented = 0;
+ for (Function::iterator FI = F.begin(), FE = F.end();
+ FI != FE; ++FI) {
+ BasicBlock &BB = *FI;
+ for (BasicBlock::iterator BI = BB.begin(), BE = BB.end();
+ BI != BE; ++BI) {
+ if (!to_instrument.count(BI)) continue;
+ // Instrument LOAD or STORE.
+ if (ClDebugMin < 0 || ClDebugMax < 0 ||
+ (n_instrumented >= ClDebugMin && n_instrumented <= ClDebugMax)) {
+ if (isa<StoreInst>(BI) || isa<LoadInst>(BI))
+ instrumentMop(BI);
+ else
+ instrumentMemIntrinsic(cast<MemIntrinsic>(BI));
+ }
+ n_instrumented++;
+ // BI is put into a separate block, so we need to stop processing this
+ // one, making sure we don't instrument it twice.
+ to_instrument.erase(BI);
+ break;
+ }
+ }
+ if (!ClDebugFunc.empty() || ClDebug)
+ errs() << F;
+
+ bool changed_stack = false;
+#ifdef __APPLE__
+ // In order to handle the +load methods correctly,
+ // we need to insert a call to __asan_init() before each of them.
+ // TODO(glider): write a test for it.
+ if (F.getNameStr().find(" load]") != std::string::npos) {
+ BasicBlock *BB = F.begin();
+ Instruction *Before = BB->begin();
+ Value *asan_init = F.getParent()->getOrInsertFunction("__asan_init",
+ VoidTy, NULL);
+ cast<Function>(asan_init)->setLinkage(Function::ExternalLinkage);
+ CallInst::Create(asan_init, "", Before);
+ F.dump();
+ }
+#endif
+
+ return n_instrumented > 0 || changed_stack;
+}
« no previous file with comments | « include/llvm/Transforms/Instrumentation.h ('k') | lib/Transforms/Instrumentation/CMakeLists.txt » ('j') | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b