diff options
Diffstat (limited to 'lib/Transforms/Instrumentation/AddressSanitizer.cpp')
-rw-r--r-- | lib/Transforms/Instrumentation/AddressSanitizer.cpp | 120 |
1 files changed, 85 insertions, 35 deletions
diff --git a/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/lib/Transforms/Instrumentation/AddressSanitizer.cpp index 22851b4..d77e20b 100644 --- a/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -43,9 +43,10 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" -#include "llvm/Transforms/Utils/BlackList.h" +#include "llvm/Transforms/Utils/Cloning.h" #include "llvm/Transforms/Utils/Local.h" #include "llvm/Transforms/Utils/ModuleUtils.h" +#include "llvm/Transforms/Utils/SpecialCaseList.h" #include <algorithm> #include <string> @@ -62,25 +63,27 @@ static const size_t kMaxStackMallocSize = 1 << 16; // 64K static const uintptr_t kCurrentStackFrameMagic = 0x41B58AB3; static const uintptr_t kRetiredStackFrameMagic = 0x45E0360E; -static const char *kAsanModuleCtorName = "asan.module_ctor"; -static const char *kAsanModuleDtorName = "asan.module_dtor"; -static const int kAsanCtorAndCtorPriority = 1; -static const char *kAsanReportErrorTemplate = "__asan_report_"; -static const char *kAsanReportLoadN = "__asan_report_load_n"; -static const char *kAsanReportStoreN = "__asan_report_store_n"; -static const char *kAsanRegisterGlobalsName = "__asan_register_globals"; -static const char *kAsanUnregisterGlobalsName = "__asan_unregister_globals"; -static const char *kAsanPoisonGlobalsName = "__asan_before_dynamic_init"; -static const char *kAsanUnpoisonGlobalsName = "__asan_after_dynamic_init"; -static const char *kAsanInitName = "__asan_init_v3"; -static const char *kAsanHandleNoReturnName = "__asan_handle_no_return"; -static const char *kAsanMappingOffsetName = "__asan_mapping_offset"; -static const char *kAsanMappingScaleName = "__asan_mapping_scale"; -static const char *kAsanStackMallocName = "__asan_stack_malloc"; -static const char *kAsanStackFreeName = "__asan_stack_free"; -static const char *kAsanGenPrefix = "__asan_gen_"; -static const char *kAsanPoisonStackMemoryName = "__asan_poison_stack_memory"; -static const char *kAsanUnpoisonStackMemoryName = +static const char *const kAsanModuleCtorName = "asan.module_ctor"; +static const char *const kAsanModuleDtorName = "asan.module_dtor"; +static const int kAsanCtorAndCtorPriority = 1; +static const char *const kAsanReportErrorTemplate = "__asan_report_"; +static const char *const kAsanReportLoadN = "__asan_report_load_n"; +static const char *const kAsanReportStoreN = "__asan_report_store_n"; +static const char *const kAsanRegisterGlobalsName = "__asan_register_globals"; +static const char *const kAsanUnregisterGlobalsName = + "__asan_unregister_globals"; +static const char *const kAsanPoisonGlobalsName = "__asan_before_dynamic_init"; +static const char *const kAsanUnpoisonGlobalsName = "__asan_after_dynamic_init"; +static const char *const kAsanInitName = "__asan_init_v3"; +static const char *const kAsanHandleNoReturnName = "__asan_handle_no_return"; +static const char *const kAsanMappingOffsetName = "__asan_mapping_offset"; +static const char *const kAsanMappingScaleName = "__asan_mapping_scale"; +static const char *const kAsanStackMallocName = "__asan_stack_malloc"; +static const char *const kAsanStackFreeName = "__asan_stack_free"; +static const char *const kAsanGenPrefix = "__asan_gen_"; +static const char *const kAsanPoisonStackMemoryName = + "__asan_poison_stack_memory"; +static const char *const kAsanUnpoisonStackMemoryName = "__asan_unpoison_stack_memory"; static const int kAsanStackLeftRedzoneMagic = 0xf1; @@ -131,6 +134,19 @@ static cl::opt<std::string> ClBlacklistFile("asan-blacklist", cl::desc("File containing the list of objects to ignore " "during instrumentation"), cl::Hidden); +// This is an experimental feature that will allow to choose between +// instrumented and non-instrumented code at link-time. +// If this option is on, just before instrumenting a function we create its +// clone; if the function is not changed by asan the clone is deleted. +// If we end up with a clone, we put the instrumented function into a section +// called "ASAN" and the uninstrumented function into a section called "NOASAN". +// +// This is still a prototype, we need to figure out a way to keep two copies of +// a function so that the linker can easily choose one of them. +static cl::opt<bool> ClKeepUninstrumented("asan-keep-uninstrumented-functions", + cl::desc("Keep uninstrumented copies of functions"), + cl::Hidden, cl::init(false)); + // These flags allow to change the shadow mapping. // The shadow mapping looks like // Shadow = (Mem >> scale) + (1 << offset_log) @@ -207,7 +223,8 @@ static ShadowMapping getShadowMapping(const Module &M, int LongSize, llvm::Triple TargetTriple(M.getTargetTriple()); bool IsAndroid = TargetTriple.getEnvironment() == llvm::Triple::Android; bool IsMacOSX = TargetTriple.getOS() == llvm::Triple::MacOSX; - bool IsPPC64 = TargetTriple.getArch() == llvm::Triple::ppc64; + bool IsPPC64 = TargetTriple.getArch() == llvm::Triple::ppc64 || + TargetTriple.getArch() == llvm::Triple::ppc64le; bool IsX86_64 = TargetTriple.getArch() == llvm::Triple::x86_64; bool IsMIPS32 = TargetTriple.getArch() == llvm::Triple::mips || TargetTriple.getArch() == llvm::Triple::mipsel; @@ -304,7 +321,7 @@ struct AddressSanitizer : public FunctionPass { Function *AsanCtorFunction; Function *AsanInitFunction; Function *AsanHandleNoReturnFunc; - OwningPtr<BlackList> BL; + OwningPtr<SpecialCaseList> BL; // This array is indexed by AccessIsWrite and log2(AccessSize). Function *AsanErrorCallback[2][kNumberOfAccessSizes]; // This array is indexed by AccessIsWrite. @@ -344,7 +361,7 @@ class AddressSanitizerModule : public ModulePass { SmallString<64> BlacklistFile; bool ZeroBaseShadow; - OwningPtr<BlackList> BL; + OwningPtr<SpecialCaseList> BL; SetOfDynamicallyInitializedGlobals DynamicallyInitializedGlobals; Type *IntptrTy; LLVMContext *C; @@ -437,7 +454,7 @@ struct FunctionStackPoisoner : public InstVisitor<FunctionStackPoisoner> { StackAlignment = std::max(StackAlignment, AI.getAlignment()); AllocaVec.push_back(&AI); - uint64_t AlignedSize = getAlignedAllocaSize(&AI); + uint64_t AlignedSize = getAlignedAllocaSize(&AI); TotalStackSize += AlignedSize; } @@ -474,6 +491,7 @@ struct FunctionStackPoisoner : public InstVisitor<FunctionStackPoisoner> { bool isInterestingAlloca(AllocaInst &AI) { return (!AI.isArrayAllocation() && AI.isStaticAlloca() && + AI.getAlignment() <= RedzoneSize() && AI.getAllocatedType()->isSized()); } @@ -529,11 +547,11 @@ static size_t TypeSizeToSizeIndex(uint32_t TypeSize) { return Res; } -// Create a constant for Str so that we can pass it to the run-time lib. +// \brief 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); GlobalVariable *GV = new GlobalVariable(M, StrConst->getType(), true, - GlobalValue::PrivateLinkage, StrConst, + GlobalValue::InternalLinkage, StrConst, kAsanGenPrefix); GV->setUnnamedAddr(true); // Ok to merge these. GV->setAlignment(1); // Strings may not be merged w/o setting align 1. @@ -865,7 +883,7 @@ bool AddressSanitizerModule::runOnModule(Module &M) { TD = getAnalysisIfAvailable<DataLayout>(); if (!TD) return false; - BL.reset(new BlackList(BlacklistFile)); + BL.reset(new SpecialCaseList(BlacklistFile)); if (BL->isIn(M)) return false; C = &(M.getContext()); int LongSize = TD->getPointerSizeInBits(); @@ -933,7 +951,7 @@ bool AddressSanitizerModule::runOnModule(Module &M) { bool GlobalHasDynamicInitializer = DynamicallyInitializedGlobals.Contains(G); // Don't check initialization order if this global is blacklisted. - GlobalHasDynamicInitializer &= !BL->isInInit(*G); + GlobalHasDynamicInitializer &= !BL->isIn(*G, "init"); StructType *NewTy = StructType::get(Ty, RightRedZoneTy, NULL); Constant *NewInitializer = ConstantStruct::get( @@ -943,8 +961,11 @@ bool AddressSanitizerModule::runOnModule(Module &M) { GlobalVariable *Name = createPrivateGlobalForString(M, G->getName()); // Create a new global variable with enough space for a redzone. + GlobalValue::LinkageTypes Linkage = G->getLinkage(); + if (G->isConstant() && Linkage == GlobalValue::PrivateLinkage) + Linkage = GlobalValue::InternalLinkage; GlobalVariable *NewGlobal = new GlobalVariable( - M, NewTy, G->isConstant(), G->getLinkage(), + M, NewTy, G->isConstant(), Linkage, NewInitializer, "", G, G->getThreadLocalMode()); NewGlobal->copyAttributesFrom(G); NewGlobal->setAlignment(MinRZ); @@ -977,7 +998,7 @@ bool AddressSanitizerModule::runOnModule(Module &M) { ArrayType *ArrayOfGlobalStructTy = ArrayType::get(GlobalStructTy, n); GlobalVariable *AllGlobals = new GlobalVariable( - M, ArrayOfGlobalStructTy, false, GlobalVariable::PrivateLinkage, + M, ArrayOfGlobalStructTy, false, GlobalVariable::InternalLinkage, ConstantArray::get(ArrayOfGlobalStructTy, Initializers), ""); // Create calls for poisoning before initializers run and unpoisoning after. @@ -1055,7 +1076,7 @@ bool AddressSanitizer::doInitialization(Module &M) { if (!TD) return false; - BL.reset(new BlackList(BlacklistFile)); + BL.reset(new SpecialCaseList(BlacklistFile)); DynamicallyInitializedGlobals.Init(M); C = &(M.getContext()); @@ -1106,8 +1127,7 @@ bool AddressSanitizer::runOnFunction(Function &F) { // If needed, insert __asan_init before checking for SanitizeAddress attr. maybeInsertAsanInitAtFunctionEntry(F); - if (!F.getAttributes().hasAttribute(AttributeSet::FunctionIndex, - Attribute::SanitizeAddress)) + if (!F.hasFnAttribute(Attribute::SanitizeAddress)) return false; if (!ClDebugFunc.empty() && ClDebugFunc != F.getName()) @@ -1118,6 +1138,7 @@ bool AddressSanitizer::runOnFunction(Function &F) { SmallSet<Value*, 16> TempsToInstrument; SmallVector<Instruction*, 16> ToInstrument; SmallVector<Instruction*, 8> NoReturnCalls; + int NumAllocas = 0; bool IsWrite; // Fill the set of memory operations to instrument. @@ -1136,6 +1157,8 @@ bool AddressSanitizer::runOnFunction(Function &F) { } else if (isa<MemIntrinsic>(BI) && ClMemIntrin) { // ok, take it. } else { + if (isa<AllocaInst>(BI)) + NumAllocas++; CallSite CS(BI); if (CS) { // A call inside BB. @@ -1152,6 +1175,17 @@ bool AddressSanitizer::runOnFunction(Function &F) { } } + Function *UninstrumentedDuplicate = 0; + bool LikelyToInstrument = + !NoReturnCalls.empty() || !ToInstrument.empty() || (NumAllocas > 0); + if (ClKeepUninstrumented && LikelyToInstrument) { + ValueToValueMapTy VMap; + UninstrumentedDuplicate = CloneFunction(&F, VMap, false); + UninstrumentedDuplicate->removeFnAttr(Attribute::SanitizeAddress); + UninstrumentedDuplicate->setName("NOASAN_" + F.getName()); + F.getParent()->getFunctionList().push_back(UninstrumentedDuplicate); + } + // Instrument. int NumInstrumented = 0; for (size_t i = 0, n = ToInstrument.size(); i != n; i++) { @@ -1176,9 +1210,25 @@ bool AddressSanitizer::runOnFunction(Function &F) { IRBuilder<> IRB(CI); IRB.CreateCall(AsanHandleNoReturnFunc); } - DEBUG(dbgs() << "ASAN done instrumenting:\n" << F << "\n"); - return NumInstrumented > 0 || ChangedStack || !NoReturnCalls.empty(); + bool res = NumInstrumented > 0 || ChangedStack || !NoReturnCalls.empty(); + DEBUG(dbgs() << "ASAN done instrumenting: " << res << " " << F << "\n"); + + if (ClKeepUninstrumented) { + if (!res) { + // No instrumentation is done, no need for the duplicate. + if (UninstrumentedDuplicate) + UninstrumentedDuplicate->eraseFromParent(); + } else { + // The function was instrumented. We must have the duplicate. + assert(UninstrumentedDuplicate); + UninstrumentedDuplicate->setSection("NOASAN"); + assert(!F.hasSection()); + F.setSection("ASAN"); + } + } + + return res; } static uint64_t ValueForPoison(uint64_t PoisonByte, size_t ShadowRedzoneSize) { |