diff options
Diffstat (limited to 'lib/Transforms/Instrumentation/AddressSanitizer.cpp')
-rw-r--r-- | lib/Transforms/Instrumentation/AddressSanitizer.cpp | 149 |
1 files changed, 93 insertions, 56 deletions
diff --git a/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/lib/Transforms/Instrumentation/AddressSanitizer.cpp index 6af44354225c..f1558c75cb90 100644 --- a/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -109,6 +109,7 @@ static const uint64_t kFreeBSD_ShadowOffset32 = 1ULL << 30; static const uint64_t kFreeBSD_ShadowOffset64 = 1ULL << 46; static const uint64_t kNetBSD_ShadowOffset32 = 1ULL << 30; static const uint64_t kNetBSD_ShadowOffset64 = 1ULL << 46; +static const uint64_t kNetBSDKasan_ShadowOffset64 = 0xdfff900000000000; static const uint64_t kPS4CPU_ShadowOffset64 = 1ULL << 40; static const uint64_t kWindowsShadowOffset32 = 3ULL << 28; @@ -344,10 +345,14 @@ static cl::opt<uint32_t> ClForceExperiment( cl::init(0)); static cl::opt<bool> - ClUsePrivateAliasForGlobals("asan-use-private-alias", - cl::desc("Use private aliases for global" - " variables"), - cl::Hidden, cl::init(false)); + ClUsePrivateAlias("asan-use-private-alias", + cl::desc("Use private aliases for global variables"), + cl::Hidden, cl::init(false)); + +static cl::opt<bool> + ClUseOdrIndicator("asan-use-odr-indicator", + cl::desc("Use odr indicators to improve ODR reporting"), + cl::Hidden, cl::init(false)); static cl::opt<bool> ClUseGlobalsGC("asan-globals-live-support", @@ -436,8 +441,11 @@ public: for (auto MDN : Globals->operands()) { // Metadata node contains the global and the fields of "Entry". assert(MDN->getNumOperands() == 5); - auto *GV = mdconst::extract_or_null<GlobalVariable>(MDN->getOperand(0)); + auto *V = mdconst::extract_or_null<Constant>(MDN->getOperand(0)); // The optimizer may optimize away a global entirely. + if (!V) continue; + auto *StrippedV = V->stripPointerCasts(); + auto *GV = dyn_cast<GlobalVariable>(StrippedV); if (!GV) continue; // We can already have an entry for GV if it was merged with another // global. @@ -538,11 +546,14 @@ static ShadowMapping getShadowMapping(Triple &TargetTriple, int LongSize, Mapping.Offset = kPPC64_ShadowOffset64; else if (IsSystemZ) Mapping.Offset = kSystemZ_ShadowOffset64; - else if (IsFreeBSD) + else if (IsFreeBSD && !IsMIPS64) Mapping.Offset = kFreeBSD_ShadowOffset64; - else if (IsNetBSD) - Mapping.Offset = kNetBSD_ShadowOffset64; - else if (IsPS4CPU) + else if (IsNetBSD) { + if (IsKasan) + Mapping.Offset = kNetBSDKasan_ShadowOffset64; + else + Mapping.Offset = kNetBSD_ShadowOffset64; + } else if (IsPS4CPU) Mapping.Offset = kPS4CPU_ShadowOffset64; else if (IsLinux && IsX86_64) { if (IsKasan) @@ -731,9 +742,12 @@ public: explicit AddressSanitizerModule(bool CompileKernel = false, bool Recover = false, - bool UseGlobalsGC = true) - : ModulePass(ID), - UseGlobalsGC(UseGlobalsGC && ClUseGlobalsGC), + bool UseGlobalsGC = true, + bool UseOdrIndicator = false) + : ModulePass(ID), UseGlobalsGC(UseGlobalsGC && ClUseGlobalsGC), + // Enable aliases as they should have no downside with ODR indicators. + UsePrivateAlias(UseOdrIndicator || ClUsePrivateAlias), + UseOdrIndicator(UseOdrIndicator || ClUseOdrIndicator), // Not a typo: ClWithComdat is almost completely pointless without // ClUseGlobalsGC (because then it only works on modules without // globals, which are rare); it is a prerequisite for ClUseGlobalsGC; @@ -742,11 +756,10 @@ public: // ClWithComdat and ClUseGlobalsGC unless the frontend says it's ok to // do globals-gc. UseCtorComdat(UseGlobalsGC && ClWithComdat) { - this->Recover = ClRecover.getNumOccurrences() > 0 ? - ClRecover : Recover; - this->CompileKernel = ClEnableKasan.getNumOccurrences() > 0 ? - ClEnableKasan : CompileKernel; - } + this->Recover = ClRecover.getNumOccurrences() > 0 ? ClRecover : Recover; + this->CompileKernel = + ClEnableKasan.getNumOccurrences() > 0 ? ClEnableKasan : CompileKernel; + } bool runOnModule(Module &M) override; StringRef getPassName() const override { return "AddressSanitizerModule"; } @@ -790,6 +803,8 @@ private: bool CompileKernel; bool Recover; bool UseGlobalsGC; + bool UsePrivateAlias; + bool UseOdrIndicator; bool UseCtorComdat; Type *IntptrTy; LLVMContext *C; @@ -990,7 +1005,7 @@ struct FunctionStackPoisoner : public InstVisitor<FunctionStackPoisoner> { if (ID == Intrinsic::localescape) LocalEscapeCall = &II; if (!ASan.UseAfterScope) return; - if (ID != Intrinsic::lifetime_start && ID != Intrinsic::lifetime_end) + if (!II.isLifetimeStartOrEnd()) return; // Found lifetime intrinsic, add ASan instrumentation if necessary. ConstantInt *Size = dyn_cast<ConstantInt>(II.getArgOperand(0)); @@ -1089,9 +1104,11 @@ INITIALIZE_PASS( ModulePass *llvm::createAddressSanitizerModulePass(bool CompileKernel, bool Recover, - bool UseGlobalsGC) { + bool UseGlobalsGC, + bool UseOdrIndicator) { assert(!CompileKernel || Recover); - return new AddressSanitizerModule(CompileKernel, Recover, UseGlobalsGC); + return new AddressSanitizerModule(CompileKernel, Recover, UseGlobalsGC, + UseOdrIndicator); } static size_t TypeSizeToSizeIndex(uint32_t TypeSize) { @@ -1100,25 +1117,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. -static GlobalVariable *createPrivateGlobalForString(Module &M, StringRef Str, - bool AllowMerging) { - Constant *StrConst = ConstantDataArray::getString(M.getContext(), Str); - // We use private linkage for module-local strings. If they can be merged - // with another one, we set the unnamed_addr attribute. - GlobalVariable *GV = - new GlobalVariable(M, StrConst->getType(), true, - GlobalValue::PrivateLinkage, StrConst, kAsanGenPrefix); - if (AllowMerging) GV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); - GV->setAlignment(1); // Strings may not be merged w/o setting align 1. - return GV; -} - /// Create a global describing a source location. static GlobalVariable *createPrivateGlobalForSourceLoc(Module &M, LocationMetadata MD) { Constant *LocData[] = { - createPrivateGlobalForString(M, MD.Filename, true), + createPrivateGlobalForString(M, MD.Filename, true, kAsanGenPrefix), ConstantInt::get(Type::getInt32Ty(M.getContext()), MD.LineNo), ConstantInt::get(Type::getInt32Ty(M.getContext()), MD.ColumnNo), }; @@ -1132,6 +1135,10 @@ static GlobalVariable *createPrivateGlobalForSourceLoc(Module &M, /// Check if \p G has been created by a trusted compiler pass. static bool GlobalWasGeneratedByCompiler(GlobalVariable *G) { + // Do not instrument @llvm.global_ctors, @llvm.used, etc. + if (G->getName().startswith("llvm.")) + return true; + // Do not instrument asan globals. if (G->getName().startswith(kAsanGenPrefix) || G->getName().startswith(kSanCovGenPrefix) || @@ -1379,7 +1386,7 @@ static void instrumentMaskedLoadOrStore(AddressSanitizer *Pass, } else { IRBuilder<> IRB(I); Value *MaskElem = IRB.CreateExtractElement(Mask, Idx); - TerminatorInst *ThenTerm = SplitBlockAndInsertIfThen(MaskElem, I, false); + Instruction *ThenTerm = SplitBlockAndInsertIfThen(MaskElem, I, false); InsertBefore = ThenTerm; } @@ -1532,8 +1539,9 @@ void AddressSanitizer::instrumentAddress(Instruction *OrigIns, Value *TagCheck = IRB.CreateICmpEQ(Tag, ConstantInt::get(IntptrTy, kMyriadDDRTag)); - TerminatorInst *TagCheckTerm = SplitBlockAndInsertIfThen( - TagCheck, InsertBefore, false, MDBuilder(*C).createBranchWeights(1, 100000)); + Instruction *TagCheckTerm = + SplitBlockAndInsertIfThen(TagCheck, InsertBefore, false, + MDBuilder(*C).createBranchWeights(1, 100000)); assert(cast<BranchInst>(TagCheckTerm)->isUnconditional()); IRB.SetInsertPoint(TagCheckTerm); InsertBefore = TagCheckTerm; @@ -1549,12 +1557,12 @@ void AddressSanitizer::instrumentAddress(Instruction *OrigIns, Value *Cmp = IRB.CreateICmpNE(ShadowValue, CmpVal); size_t Granularity = 1ULL << Mapping.Scale; - TerminatorInst *CrashTerm = nullptr; + Instruction *CrashTerm = nullptr; if (ClAlwaysSlowPath || (TypeSize < 8 * Granularity)) { // We use branch weights for the slow path check, to indicate that the slow // path is rarely taken. This seems to be the case for SPEC benchmarks. - TerminatorInst *CheckTerm = SplitBlockAndInsertIfThen( + Instruction *CheckTerm = SplitBlockAndInsertIfThen( Cmp, InsertBefore, false, MDBuilder(*C).createBranchWeights(1, 100000)); assert(cast<BranchInst>(CheckTerm)->isUnconditional()); BasicBlock *NextBB = CheckTerm->getSuccessor(0); @@ -1653,14 +1661,6 @@ bool AddressSanitizerModule::ShouldInstrumentGlobal(GlobalVariable *G) { if (!Ty->isSized()) return false; if (!G->hasInitializer()) return false; if (GlobalWasGeneratedByCompiler(G)) return false; // Our own globals. - // Touch only those globals that will not be defined in other modules. - // Don't handle ODR linkage types and COMDATs since other modules may be built - // without ASan. - if (G->getLinkage() != GlobalVariable::ExternalLinkage && - G->getLinkage() != GlobalVariable::PrivateLinkage && - G->getLinkage() != GlobalVariable::InternalLinkage) - return false; - if (G->hasComdat()) return false; // Two problems with thread-locals: // - The address of the main thread's copy can't be computed at link-time. // - Need to poison all copies, not just the main thread's one. @@ -1668,6 +1668,33 @@ bool AddressSanitizerModule::ShouldInstrumentGlobal(GlobalVariable *G) { // For now, just ignore this Global if the alignment is large. if (G->getAlignment() > MinRedzoneSizeForGlobal()) return false; + // For non-COFF targets, only instrument globals known to be defined by this + // TU. + // FIXME: We can instrument comdat globals on ELF if we are using the + // GC-friendly metadata scheme. + if (!TargetTriple.isOSBinFormatCOFF()) { + if (!G->hasExactDefinition() || G->hasComdat()) + return false; + } else { + // On COFF, don't instrument non-ODR linkages. + if (G->isInterposable()) + return false; + } + + // If a comdat is present, it must have a selection kind that implies ODR + // semantics: no duplicates, any, or exact match. + if (Comdat *C = G->getComdat()) { + switch (C->getSelectionKind()) { + case Comdat::Any: + case Comdat::ExactMatch: + case Comdat::NoDuplicates: + break; + case Comdat::Largest: + case Comdat::SameSize: + return false; + } + } + if (G->hasSection()) { StringRef Section = G->getSection(); @@ -2082,7 +2109,7 @@ bool AddressSanitizerModule::InstrumentGlobals(IRBuilder<> &IRB, Module &M, bool // We shouldn't merge same module names, as this string serves as unique // module ID in runtime. GlobalVariable *ModuleName = createPrivateGlobalForString( - M, M.getModuleIdentifier(), /*AllowMerging*/ false); + M, M.getModuleIdentifier(), /*AllowMerging*/ false, kAsanGenPrefix); for (size_t i = 0; i < n; i++) { static const uint64_t kMaxGlobalRedzone = 1 << 18; @@ -2094,7 +2121,7 @@ bool AddressSanitizerModule::InstrumentGlobals(IRBuilder<> &IRB, Module &M, bool // if it's available, otherwise just write the name of global variable). GlobalVariable *Name = createPrivateGlobalForString( M, MD.Name.empty() ? NameForGlobal : MD.Name, - /*AllowMerging*/ true); + /*AllowMerging*/ true, kAsanGenPrefix); Type *Ty = G->getValueType(); uint64_t SizeInBytes = DL.getTypeAllocSize(Ty); @@ -2121,7 +2148,12 @@ bool AddressSanitizerModule::InstrumentGlobals(IRBuilder<> &IRB, Module &M, bool new GlobalVariable(M, NewTy, G->isConstant(), Linkage, NewInitializer, "", G, G->getThreadLocalMode()); NewGlobal->copyAttributesFrom(G); + NewGlobal->setComdat(G->getComdat()); NewGlobal->setAlignment(MinRZ); + // Don't fold globals with redzones. ODR violation detector and redzone + // poisoning implicitly creates a dependence on the global's address, so it + // is no longer valid for it to be marked unnamed_addr. + NewGlobal->setUnnamedAddr(GlobalValue::UnnamedAddr::None); // Move null-terminated C strings to "__asan_cstring" section on Darwin. if (TargetTriple.isOSBinFormatMachO() && !G->hasSection() && @@ -2162,12 +2194,18 @@ bool AddressSanitizerModule::InstrumentGlobals(IRBuilder<> &IRB, Module &M, bool bool CanUsePrivateAliases = TargetTriple.isOSBinFormatELF() || TargetTriple.isOSBinFormatMachO() || TargetTriple.isOSBinFormatWasm(); - if (CanUsePrivateAliases && ClUsePrivateAliasForGlobals) { + if (CanUsePrivateAliases && UsePrivateAlias) { // Create local alias for NewGlobal to avoid crash on ODR between // instrumented and non-instrumented libraries. - auto *GA = GlobalAlias::create(GlobalValue::InternalLinkage, - NameForGlobal + M.getName(), NewGlobal); + InstrumentedGlobal = + GlobalAlias::create(GlobalValue::PrivateLinkage, "", NewGlobal); + } + // ODR should not happen for local linkage. + if (NewGlobal->hasLocalLinkage()) { + ODRIndicator = ConstantExpr::getIntToPtr(ConstantInt::get(IntptrTy, -1), + IRB.getInt8PtrTy()); + } else if (UseOdrIndicator) { // With local aliases, we need to provide another externally visible // symbol __odr_asan_XXX to detect ODR violation. auto *ODRIndicatorSym = @@ -2181,7 +2219,6 @@ bool AddressSanitizerModule::InstrumentGlobals(IRBuilder<> &IRB, Module &M, bool ODRIndicatorSym->setDLLStorageClass(NewGlobal->getDLLStorageClass()); ODRIndicatorSym->setAlignment(1); ODRIndicator = ODRIndicatorSym; - InstrumentedGlobal = GA; } Constant *Initializer = ConstantStruct::get( @@ -2996,7 +3033,7 @@ void FunctionStackPoisoner::processStaticAllocas() { IntptrPtrTy); GlobalVariable *StackDescriptionGlobal = createPrivateGlobalForString(*F.getParent(), DescriptionString, - /*AllowMerging*/ true); + /*AllowMerging*/ true, kAsanGenPrefix); Value *Description = IRB.CreatePointerCast(StackDescriptionGlobal, IntptrTy); IRB.CreateStore(Description, BasePlus1); // Write the PC to redzone[2]. @@ -3054,7 +3091,7 @@ void FunctionStackPoisoner::processStaticAllocas() { // <This is not a fake stack; unpoison the redzones> Value *Cmp = IRBRet.CreateICmpNE(FakeStack, Constant::getNullValue(IntptrTy)); - TerminatorInst *ThenTerm, *ElseTerm; + Instruction *ThenTerm, *ElseTerm; SplitBlockAndInsertIfThenElse(Cmp, Ret, &ThenTerm, &ElseTerm); IRBuilder<> IRBPoison(ThenTerm); |