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; |
+} |