diff --git a/bindings/go/llvm/InstrumentationBindings.cpp b/bindings/go/llvm/InstrumentationBindings.cpp index 316f7774344..794657fbce3 100644 --- a/bindings/go/llvm/InstrumentationBindings.cpp +++ b/bindings/go/llvm/InstrumentationBindings.cpp @@ -15,6 +15,7 @@ #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Module.h" #include "llvm/Transforms/Instrumentation.h" +#include "llvm/Transforms/Instrumentation/AddressSanitizer.h" #include "llvm/Transforms/Instrumentation/MemorySanitizer.h" #include "llvm/Transforms/Instrumentation/ThreadSanitizer.h" @@ -25,7 +26,7 @@ void LLVMAddAddressSanitizerFunctionPass(LLVMPassManagerRef PM) { } void LLVMAddAddressSanitizerModulePass(LLVMPassManagerRef PM) { - unwrap(PM)->add(createAddressSanitizerModulePass()); + unwrap(PM)->add(createModuleAddressSanitizerLegacyPassPass()); } void LLVMAddThreadSanitizerPass(LLVMPassManagerRef PM) { diff --git a/include/llvm/InitializePasses.h b/include/llvm/InitializePasses.h index fe6c17182a8..acc7065de98 100644 --- a/include/llvm/InitializePasses.h +++ b/include/llvm/InitializePasses.h @@ -64,8 +64,9 @@ void initializeAAEvalLegacyPassPass(PassRegistry&); void initializeAAResultsWrapperPassPass(PassRegistry&); void initializeADCELegacyPassPass(PassRegistry&); void initializeAddDiscriminatorsLegacyPassPass(PassRegistry&); -void initializeAddressSanitizerModulePass(PassRegistry&); -void initializeAddressSanitizerPass(PassRegistry&); +void initializeModuleAddressSanitizerLegacyPassPass(PassRegistry &); +void initializeASanGlobalsMetadataWrapperPassPass(PassRegistry &); +void initializeAddressSanitizerLegacyPassPass(PassRegistry &); void initializeAggressiveInstCombinerLegacyPassPass(PassRegistry&); void initializeAliasSetPrinterPass(PassRegistry&); void initializeAlignmentFromAssumptionsPass(PassRegistry&); diff --git a/include/llvm/Transforms/Instrumentation.h b/include/llvm/Transforms/Instrumentation.h index 29cb2818136..ff0ebf75245 100644 --- a/include/llvm/Transforms/Instrumentation.h +++ b/include/llvm/Transforms/Instrumentation.h @@ -142,15 +142,6 @@ struct InstrProfOptions { ModulePass *createInstrProfilingLegacyPass( const InstrProfOptions &Options = InstrProfOptions()); -// Insert AddressSanitizer (address sanity checking) instrumentation -FunctionPass *createAddressSanitizerFunctionPass(bool CompileKernel = false, - bool Recover = false, - bool UseAfterScope = false); -ModulePass *createAddressSanitizerModulePass(bool CompileKernel = false, - bool Recover = false, - bool UseGlobalsGC = true, - bool UseOdrIndicator = true); - FunctionPass *createHWAddressSanitizerPass(bool CompileKernel = false, bool Recover = false); diff --git a/include/llvm/Transforms/Instrumentation/AddressSanitizer.h b/include/llvm/Transforms/Instrumentation/AddressSanitizer.h new file mode 100644 index 00000000000..40007a9b8c5 --- /dev/null +++ b/include/llvm/Transforms/Instrumentation/AddressSanitizer.h @@ -0,0 +1,143 @@ +//===--------- Definition of the AddressSanitizer class ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the AddressSanitizer class which is a port of the legacy +// AddressSanitizer pass to use the new PassManager infrastructure. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_TRANSFORMS_INSTRUMENTATION_ADDRESSSANITIZERPASS_H +#define LLVM_TRANSFORMS_INSTRUMENTATION_ADDRESSSANITIZERPASS_H + +#include "llvm/IR/Function.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +/// Frontend-provided metadata for source location. +struct LocationMetadata { + StringRef Filename; + int LineNo = 0; + int ColumnNo = 0; + + LocationMetadata() = default; + + bool empty() const { return Filename.empty(); } + void parse(MDNode *MDN); +}; + +/// Frontend-provided metadata for global variables. +class GlobalsMetadata { +public: + struct Entry { + LocationMetadata SourceLoc; + StringRef Name; + bool IsDynInit = false; + bool IsBlacklisted = false; + + Entry() = default; + }; + + /// Create a default uninitialized GlobalsMetadata instance. + GlobalsMetadata() = default; + + /// Create an initialized GlobalsMetadata instance. + GlobalsMetadata(Module &M); + + /// Returns metadata entry for a given global. + Entry get(GlobalVariable *G) const { + auto Pos = Entries.find(G); + return (Pos != Entries.end()) ? Pos->second : Entry(); + } + + /// Handle invalidation from the pass manager. + /// These results are never invalidated. + bool invalidate(Module &, const PreservedAnalyses &, + ModuleAnalysisManager::Invalidator &) { + return false; + } + bool invalidate(Function &, const PreservedAnalyses &, + FunctionAnalysisManager::Invalidator &) { + return false; + } + +private: + DenseMap Entries; +}; + +/// The ASanGlobalsMetadataAnalysis initializes and returns a GlobalsMetadata +/// object. More specifically, ASan requires looking at all globals registered +/// in 'llvm.asan.globals' before running, which only depends on reading module +/// level metadata. This analysis is required to run before running the +/// AddressSanitizerPass since it collects that metadata. +/// The legacy pass manager equivalent of this is ASanGlobalsMetadataLegacyPass. +class ASanGlobalsMetadataAnalysis + : public AnalysisInfoMixin { +public: + using Result = GlobalsMetadata; + + Result run(Module &, ModuleAnalysisManager &); + +private: + friend AnalysisInfoMixin; + static AnalysisKey Key; +}; + +/// Public interface to the address sanitizer pass for instrumenting code to +/// check for various memory errors at runtime. +/// +/// The sanitizer itself is a function pass that works by inserting various +/// calls to the ASan runtime library functions. The runtime library essentially +/// replaces malloc() and free() with custom implementations that allow regions +/// surrounding requested memory to be checked for invalid accesses. +class AddressSanitizerPass : public PassInfoMixin { +public: + explicit AddressSanitizerPass(bool CompileKernel = false, + bool Recover = false, + bool UseAfterScope = false); + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); + +private: + bool CompileKernel; + bool Recover; + bool UseAfterScope; +}; + +/// Public interface to the address sanitizer module pass for instrumenting code +/// to check for various memory errors. +/// +/// This adds 'asan.module_ctor' to 'llvm.global_ctors'. This pass may also +/// run intependently of the function address sanitizer. +class ModuleAddressSanitizerPass + : public PassInfoMixin { +public: + explicit ModuleAddressSanitizerPass(bool CompileKernel = false, + bool Recover = false, + bool UseGlobalGC = true, + bool UseOdrIndicator = false); + PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); + +private: + bool CompileKernel; + bool Recover; + bool UseGlobalGC; + bool UseOdrIndicator; +}; + +// Insert AddressSanitizer (address sanity checking) instrumentation +FunctionPass *createAddressSanitizerFunctionPass(bool CompileKernel = false, + bool Recover = false, + bool UseAfterScope = false); +ModulePass *createModuleAddressSanitizerLegacyPassPass( + bool CompileKernel = false, bool Recover = false, bool UseGlobalsGC = true, + bool UseOdrIndicator = true); + +} // namespace llvm + +#endif diff --git a/lib/Passes/PassBuilder.cpp b/lib/Passes/PassBuilder.cpp index 8e62c1d0b69..2e7d7121249 100644 --- a/lib/Passes/PassBuilder.cpp +++ b/lib/Passes/PassBuilder.cpp @@ -88,14 +88,15 @@ #include "llvm/Transforms/IPO/WholeProgramDevirt.h" #include "llvm/Transforms/InstCombine/InstCombine.h" #include "llvm/Transforms/Instrumentation.h" +#include "llvm/Transforms/Instrumentation/AddressSanitizer.h" #include "llvm/Transforms/Instrumentation/BoundsChecking.h" #include "llvm/Transforms/Instrumentation/CGProfile.h" #include "llvm/Transforms/Instrumentation/ControlHeightReduction.h" #include "llvm/Transforms/Instrumentation/GCOVProfiler.h" #include "llvm/Transforms/Instrumentation/InstrProfiling.h" #include "llvm/Transforms/Instrumentation/MemorySanitizer.h" -#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h" #include "llvm/Transforms/Instrumentation/PGOInstrumentation.h" +#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h" #include "llvm/Transforms/Scalar/ADCE.h" #include "llvm/Transforms/Scalar/AlignmentFromAssumptions.h" #include "llvm/Transforms/Scalar/BDCE.h" diff --git a/lib/Passes/PassRegistry.def b/lib/Passes/PassRegistry.def index ac193f5cae1..1cc38897692 100644 --- a/lib/Passes/PassRegistry.def +++ b/lib/Passes/PassRegistry.def @@ -27,6 +27,7 @@ MODULE_ANALYSIS("stack-safety", StackSafetyGlobalAnalysis()) MODULE_ANALYSIS("targetlibinfo", TargetLibraryAnalysis()) MODULE_ANALYSIS("verify", VerifierAnalysis()) MODULE_ANALYSIS("pass-instrumentation", PassInstrumentationAnalysis(PIC)) +MODULE_ANALYSIS("asan-globals-md", ASanGlobalsMetadataAnalysis()) #ifndef MODULE_ALIAS_ANALYSIS #define MODULE_ALIAS_ANALYSIS(NAME, CREATE_PASS) \ @@ -81,6 +82,7 @@ MODULE_PASS("strip-dead-prototypes", StripDeadPrototypesPass()) MODULE_PASS("synthetic-counts-propagation", SyntheticCountsPropagation()) MODULE_PASS("wholeprogramdevirt", WholeProgramDevirtPass(nullptr, nullptr)) MODULE_PASS("verify", VerifierPass()) +MODULE_PASS("asan-module", ModuleAddressSanitizerPass(false, false, true, false)) #undef MODULE_PASS #ifndef CGSCC_ANALYSIS @@ -231,6 +233,7 @@ FUNCTION_PASS("verify", RegionInfoVerifierPass()) FUNCTION_PASS("view-cfg", CFGViewerPass()) FUNCTION_PASS("view-cfg-only", CFGOnlyViewerPass()) FUNCTION_PASS("transform-warning", WarnMissedTransformationsPass()) +FUNCTION_PASS("asan", AddressSanitizerPass(false, false, false)) FUNCTION_PASS("msan", MemorySanitizerPass({})) FUNCTION_PASS("tsan", ThreadSanitizerPass()) #undef FUNCTION_PASS diff --git a/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/lib/Transforms/Instrumentation/AddressSanitizer.cpp index e95b88b579c..5a3f6a12bf0 100644 --- a/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -12,6 +12,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Transforms/Instrumentation/AddressSanitizer.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DepthFirstIterator.h" @@ -24,7 +25,6 @@ #include "llvm/ADT/Twine.h" #include "llvm/Analysis/MemoryBuiltins.h" #include "llvm/Analysis/TargetLibraryInfo.h" -#include "llvm/Transforms/Utils/Local.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/BinaryFormat/MachO.h" #include "llvm/IR/Argument.h" @@ -71,6 +71,7 @@ #include "llvm/Transforms/Instrumentation.h" #include "llvm/Transforms/Utils/ASanStackFrameLayout.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" +#include "llvm/Transforms/Utils/Local.h" #include "llvm/Transforms/Utils/ModuleUtils.h" #include "llvm/Transforms/Utils/PromoteMemToReg.h" #include @@ -392,87 +393,6 @@ STATISTIC(NumOptimizedAccessesToStackVar, namespace { -/// Frontend-provided metadata for source location. -struct LocationMetadata { - StringRef Filename; - int LineNo = 0; - int ColumnNo = 0; - - LocationMetadata() = default; - - bool empty() const { return Filename.empty(); } - - void parse(MDNode *MDN) { - assert(MDN->getNumOperands() == 3); - MDString *DIFilename = cast(MDN->getOperand(0)); - Filename = DIFilename->getString(); - LineNo = - mdconst::extract(MDN->getOperand(1))->getLimitedValue(); - ColumnNo = - mdconst::extract(MDN->getOperand(2))->getLimitedValue(); - } -}; - -/// Frontend-provided metadata for global variables. -class GlobalsMetadata { -public: - struct Entry { - LocationMetadata SourceLoc; - StringRef Name; - bool IsDynInit = false; - bool IsBlacklisted = false; - - Entry() = default; - }; - - GlobalsMetadata() = default; - - void reset() { - inited_ = false; - Entries.clear(); - } - - void init(Module &M) { - assert(!inited_); - inited_ = true; - NamedMDNode *Globals = M.getNamedMetadata("llvm.asan.globals"); - if (!Globals) return; - for (auto MDN : Globals->operands()) { - // Metadata node contains the global and the fields of "Entry". - assert(MDN->getNumOperands() == 5); - auto *V = mdconst::extract_or_null(MDN->getOperand(0)); - // The optimizer may optimize away a global entirely. - if (!V) continue; - auto *StrippedV = V->stripPointerCasts(); - auto *GV = dyn_cast(StrippedV); - if (!GV) continue; - // We can already have an entry for GV if it was merged with another - // global. - Entry &E = Entries[GV]; - if (auto *Loc = cast_or_null(MDN->getOperand(1))) - E.SourceLoc.parse(Loc); - if (auto *Name = cast_or_null(MDN->getOperand(2))) - E.Name = Name->getString(); - ConstantInt *IsDynInit = - mdconst::extract(MDN->getOperand(3)); - E.IsDynInit |= IsDynInit->isOne(); - ConstantInt *IsBlacklisted = - mdconst::extract(MDN->getOperand(4)); - E.IsBlacklisted |= IsBlacklisted->isOne(); - } - } - - /// Returns metadata entry for a given global. - Entry get(GlobalVariable *G) const { - auto Pos = Entries.find(G); - return (Pos != Entries.end()) ? Pos->second : Entry(); - } - -private: - bool inited_ = false; - DenseMap Entries; -}; - /// This struct defines the shadow mapping using the rule: /// shadow = (mem >> Scale) ADD-or-OR Offset. /// If InGlobal is true, then @@ -606,27 +526,53 @@ static size_t RedzoneSizeForScale(int MappingScale) { namespace { -/// AddressSanitizer: instrument the code in module to find memory bugs. -struct AddressSanitizer : public FunctionPass { - // Pass identification, replacement for typeid +/// Module analysis for getting various metadata about the module. +class ASanGlobalsMetadataWrapperPass : public ModulePass { +public: static char ID; - explicit AddressSanitizer(bool CompileKernel = false, bool Recover = false, - bool UseAfterScope = false) - : FunctionPass(ID), UseAfterScope(UseAfterScope || ClUseAfterScope) { - this->Recover = ClRecover.getNumOccurrences() > 0 ? ClRecover : Recover; - this->CompileKernel = ClEnableKasan.getNumOccurrences() > 0 ? - ClEnableKasan : CompileKernel; - initializeAddressSanitizerPass(*PassRegistry::getPassRegistry()); + ASanGlobalsMetadataWrapperPass() : ModulePass(ID) { + initializeASanGlobalsMetadataWrapperPassPass( + *PassRegistry::getPassRegistry()); + } + + bool runOnModule(Module &M) override { + GlobalsMD = GlobalsMetadata(M); + return false; } StringRef getPassName() const override { - return "AddressSanitizerFunctionPass"; + return "ASanGlobalsMetadataWrapperPass"; } void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.addRequired(); - AU.addRequired(); + AU.setPreservesAll(); + } + + GlobalsMetadata &getGlobalsMD() { return GlobalsMD; } + +private: + GlobalsMetadata GlobalsMD; +}; + +char ASanGlobalsMetadataWrapperPass::ID = 0; + +/// AddressSanitizer: instrument the code in module to find memory bugs. +struct AddressSanitizer { + AddressSanitizer(Module &M, GlobalsMetadata &GlobalsMD, + bool CompileKernel = false, bool Recover = false, + bool UseAfterScope = false) + : UseAfterScope(UseAfterScope || ClUseAfterScope), GlobalsMD(GlobalsMD) { + this->Recover = ClRecover.getNumOccurrences() > 0 ? ClRecover : Recover; + this->CompileKernel = + ClEnableKasan.getNumOccurrences() > 0 ? ClEnableKasan : CompileKernel; + + C = &(M.getContext()); + LongSize = M.getDataLayout().getPointerSizeInBits(); + IntptrTy = Type::getIntNTy(*C, LongSize); + TargetTriple = Triple(M.getTargetTriple()); + + Mapping = getShadowMapping(TargetTriple, LongSize, this->CompileKernel); } uint64_t getAllocaSizeInBytes(const AllocaInst &AI) const { @@ -671,14 +617,10 @@ struct AddressSanitizer : public FunctionPass { Value *SizeArgument, uint32_t Exp); void instrumentMemIntrinsic(MemIntrinsic *MI); Value *memToShadow(Value *Shadow, IRBuilder<> &IRB); - bool runOnFunction(Function &F) override; + bool instrumentFunction(Function &F, const TargetLibraryInfo *TLI); bool maybeInsertAsanInitAtFunctionEntry(Function &F); void maybeInsertDynamicShadowAtFunctionEntry(Function &F); void markEscapedLocalAllocas(Function &F); - bool doInitialization(Module &M) override; - bool doFinalization(Module &M) override; - - DominatorTree &getDominatorTree() const { return *DT; } private: friend struct FunctionStackPoisoner; @@ -714,7 +656,6 @@ private: bool UseAfterScope; Type *IntptrTy; ShadowMapping Mapping; - DominatorTree *DT; FunctionCallee AsanHandleNoReturnFunc; FunctionCallee AsanPtrCmpFunction, AsanPtrSubFunction; Constant *AsanShadowGlobal; @@ -734,16 +675,49 @@ private: DenseMap ProcessedAllocas; }; -class AddressSanitizerModule : public ModulePass { +class AddressSanitizerLegacyPass : public FunctionPass { public: - // Pass identification, replacement for typeid static char ID; - explicit AddressSanitizerModule(bool CompileKernel = false, - bool Recover = false, - bool UseGlobalsGC = true, - bool UseOdrIndicator = false) - : ModulePass(ID), UseGlobalsGC(UseGlobalsGC && ClUseGlobalsGC), + explicit AddressSanitizerLegacyPass(bool CompileKernel = false, + bool Recover = false, + bool UseAfterScope = false) + : FunctionPass(ID), CompileKernel(CompileKernel), Recover(Recover), + UseAfterScope(UseAfterScope) { + initializeAddressSanitizerLegacyPassPass(*PassRegistry::getPassRegistry()); + } + + StringRef getPassName() const override { + return "AddressSanitizerFunctionPass"; + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired(); + AU.addRequired(); + } + + bool runOnFunction(Function &F) override { + GlobalsMetadata &GlobalsMD = + getAnalysis().getGlobalsMD(); + const TargetLibraryInfo *TLI = + &getAnalysis().getTLI(); + AddressSanitizer ASan(*F.getParent(), GlobalsMD, CompileKernel, Recover, + UseAfterScope); + return ASan.instrumentFunction(F, TLI); + } + +private: + bool CompileKernel; + bool Recover; + bool UseAfterScope; +}; + +class ModuleAddressSanitizer { +public: + ModuleAddressSanitizer(Module &M, GlobalsMetadata &GlobalsMD, + bool CompileKernel = false, bool Recover = false, + bool UseGlobalsGC = true, bool UseOdrIndicator = false) + : GlobalsMD(GlobalsMD), UseGlobalsGC(UseGlobalsGC && ClUseGlobalsGC), // Enable aliases as they should have no downside with ODR indicators. UsePrivateAlias(UseOdrIndicator || ClUsePrivateAlias), UseOdrIndicator(UseOdrIndicator || ClUseOdrIndicator), @@ -758,10 +732,15 @@ public: this->Recover = ClRecover.getNumOccurrences() > 0 ? ClRecover : Recover; this->CompileKernel = ClEnableKasan.getNumOccurrences() > 0 ? ClEnableKasan : CompileKernel; + + C = &(M.getContext()); + int LongSize = M.getDataLayout().getPointerSizeInBits(); + IntptrTy = Type::getIntNTy(*C, LongSize); + TargetTriple = Triple(M.getTargetTriple()); + Mapping = getShadowMapping(TargetTriple, LongSize, this->CompileKernel); } - bool runOnModule(Module &M) override; - StringRef getPassName() const override { return "AddressSanitizerModule"; } + bool instrumentModule(Module &); private: void initializeCallbacks(Module &M); @@ -822,6 +801,41 @@ private: Function *AsanDtorFunction = nullptr; }; +class ModuleAddressSanitizerLegacyPass : public ModulePass { +public: + static char ID; + + explicit ModuleAddressSanitizerLegacyPass(bool CompileKernel = false, + bool Recover = false, + bool UseGlobalGC = true, + bool UseOdrIndicator = false) + : ModulePass(ID), CompileKernel(CompileKernel), Recover(Recover), + UseGlobalGC(UseGlobalGC), UseOdrIndicator(UseOdrIndicator) { + initializeModuleAddressSanitizerLegacyPassPass( + *PassRegistry::getPassRegistry()); + } + + StringRef getPassName() const override { return "ModuleAddressSanitizer"; } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired(); + } + + bool runOnModule(Module &M) override { + GlobalsMetadata &GlobalsMD = + getAnalysis().getGlobalsMD(); + ModuleAddressSanitizer ASanModule(M, GlobalsMD, CompileKernel, Recover, + UseGlobalGC, UseOdrIndicator); + return ASanModule.instrumentModule(M); + } + +private: + bool CompileKernel; + bool Recover; + bool UseGlobalGC; + bool UseOdrIndicator; +}; + // Stack poisoning does not play well with exception handling. // When an exception is thrown, we essentially bypass the code // that unpoisones the stack. This is why the run-time library has @@ -875,13 +889,9 @@ struct FunctionStackPoisoner : public InstVisitor { std::unique_ptr EmptyInlineAsm; FunctionStackPoisoner(Function &F, AddressSanitizer &ASan) - : F(F), - ASan(ASan), - DIB(*F.getParent(), /*AllowUnresolved*/ false), - C(ASan.C), - IntptrTy(ASan.IntptrTy), - IntptrPtrTy(PointerType::get(IntptrTy, 0)), - Mapping(ASan.Mapping), + : F(F), ASan(ASan), DIB(*F.getParent(), /*AllowUnresolved*/ false), + C(ASan.C), IntptrTy(ASan.IntptrTy), + IntptrPtrTy(PointerType::get(IntptrTy, 0)), Mapping(ASan.Mapping), StackAlignment(1 << Mapping.Scale), EmptyInlineAsm(CallInst::Create(ASan.EmptyAsm)) {} @@ -1042,13 +1052,6 @@ struct FunctionStackPoisoner : public InstVisitor { // ---------------------- Helpers. void initializeCallbacks(Module &M); - bool doesDominateAllExits(const Instruction *I) const { - for (auto Ret : RetVec) { - if (!ASan.getDominatorTree().dominates(I, Ret)) return false; - } - return true; - } - /// Finds alloca where the value comes from. AllocaInst *findAllocaForValue(Value *V); @@ -1074,16 +1077,111 @@ struct FunctionStackPoisoner : public InstVisitor { } // end anonymous namespace -char AddressSanitizer::ID = 0; +void LocationMetadata::parse(MDNode *MDN) { + assert(MDN->getNumOperands() == 3); + MDString *DIFilename = cast(MDN->getOperand(0)); + Filename = DIFilename->getString(); + LineNo = mdconst::extract(MDN->getOperand(1))->getLimitedValue(); + ColumnNo = + mdconst::extract(MDN->getOperand(2))->getLimitedValue(); +} + +// FIXME: It would be cleaner to instead attach relevant metadata to the globals +// we want to sanitize instead and reading this metadata on each pass over a +// function instead of reading module level metadata at first. +GlobalsMetadata::GlobalsMetadata(Module &M) { + NamedMDNode *Globals = M.getNamedMetadata("llvm.asan.globals"); + if (!Globals) + return; + for (auto MDN : Globals->operands()) { + // Metadata node contains the global and the fields of "Entry". + assert(MDN->getNumOperands() == 5); + auto *V = mdconst::extract_or_null(MDN->getOperand(0)); + // The optimizer may optimize away a global entirely. + if (!V) + continue; + auto *StrippedV = V->stripPointerCasts(); + auto *GV = dyn_cast(StrippedV); + if (!GV) + continue; + // We can already have an entry for GV if it was merged with another + // global. + Entry &E = Entries[GV]; + if (auto *Loc = cast_or_null(MDN->getOperand(1))) + E.SourceLoc.parse(Loc); + if (auto *Name = cast_or_null(MDN->getOperand(2))) + E.Name = Name->getString(); + ConstantInt *IsDynInit = mdconst::extract(MDN->getOperand(3)); + E.IsDynInit |= IsDynInit->isOne(); + ConstantInt *IsBlacklisted = + mdconst::extract(MDN->getOperand(4)); + E.IsBlacklisted |= IsBlacklisted->isOne(); + } +} + +AnalysisKey ASanGlobalsMetadataAnalysis::Key; + +GlobalsMetadata ASanGlobalsMetadataAnalysis::run(Module &M, + ModuleAnalysisManager &AM) { + return GlobalsMetadata(M); +} + +AddressSanitizerPass::AddressSanitizerPass(bool CompileKernel, bool Recover, + bool UseAfterScope) + : CompileKernel(CompileKernel), Recover(Recover), + UseAfterScope(UseAfterScope) {} + +PreservedAnalyses AddressSanitizerPass::run(Function &F, + AnalysisManager &AM) { + auto &MAMProxy = AM.getResult(F); + auto &MAM = MAMProxy.getManager(); + Module &M = *F.getParent(); + if (auto *R = MAM.getCachedResult(M)) { + const TargetLibraryInfo *TLI = &AM.getResult(F); + AddressSanitizer Sanitizer(M, *R, CompileKernel, Recover, UseAfterScope); + if (Sanitizer.instrumentFunction(F, TLI)) + return PreservedAnalyses::none(); + return PreservedAnalyses::all(); + } + + report_fatal_error( + "The ASanGlobalsMetadataAnalysis is required to run before " + "AddressSanitizer can run"); + return PreservedAnalyses::all(); +} + +ModuleAddressSanitizerPass::ModuleAddressSanitizerPass(bool CompileKernel, + bool Recover, + bool UseGlobalGC, + bool UseOdrIndicator) + : CompileKernel(CompileKernel), Recover(Recover), UseGlobalGC(UseGlobalGC), + UseOdrIndicator(UseOdrIndicator) {} + +PreservedAnalyses ModuleAddressSanitizerPass::run(Module &M, + AnalysisManager &AM) { + GlobalsMetadata &GlobalsMD = AM.getResult(M); + ModuleAddressSanitizer Sanitizer(M, GlobalsMD, CompileKernel, Recover, + UseGlobalGC, UseOdrIndicator); + if (Sanitizer.instrumentModule(M)) + return PreservedAnalyses::none(); + return PreservedAnalyses::all(); +} + +INITIALIZE_PASS(ASanGlobalsMetadataWrapperPass, "asan-globals-md", + "Read metadata to mark which globals should be instrumented " + "when running ASan.", + false, true); + +char AddressSanitizerLegacyPass::ID = 0; INITIALIZE_PASS_BEGIN( - AddressSanitizer, "asan", + AddressSanitizerLegacyPass, "asan", "AddressSanitizer: detects use-after-free and out-of-bounds bugs.", false, false) -INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) +INITIALIZE_PASS_DEPENDENCY(ASanGlobalsMetadataWrapperPass) INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) INITIALIZE_PASS_END( - AddressSanitizer, "asan", + AddressSanitizerLegacyPass, "asan", "AddressSanitizer: detects use-after-free and out-of-bounds bugs.", false, false) @@ -1091,24 +1189,22 @@ FunctionPass *llvm::createAddressSanitizerFunctionPass(bool CompileKernel, bool Recover, bool UseAfterScope) { assert(!CompileKernel || Recover); - return new AddressSanitizer(CompileKernel, Recover, UseAfterScope); + return new AddressSanitizerLegacyPass(CompileKernel, Recover, UseAfterScope); } -char AddressSanitizerModule::ID = 0; +char ModuleAddressSanitizerLegacyPass::ID = 0; INITIALIZE_PASS( - AddressSanitizerModule, "asan-module", + ModuleAddressSanitizerLegacyPass, "asan-module", "AddressSanitizer: detects use-after-free and out-of-bounds bugs." "ModulePass", false, false) -ModulePass *llvm::createAddressSanitizerModulePass(bool CompileKernel, - bool Recover, - bool UseGlobalsGC, - bool UseOdrIndicator) { +ModulePass *llvm::createModuleAddressSanitizerLegacyPassPass( + bool CompileKernel, bool Recover, bool UseGlobalsGC, bool UseOdrIndicator) { assert(!CompileKernel || Recover); - return new AddressSanitizerModule(CompileKernel, Recover, UseGlobalsGC, - UseOdrIndicator); + return new ModuleAddressSanitizerLegacyPass(CompileKernel, Recover, + UseGlobalsGC, UseOdrIndicator); } static size_t TypeSizeToSizeIndex(uint32_t TypeSize) { @@ -1328,6 +1424,9 @@ bool AddressSanitizer::GlobalIsLinkerInitialized(GlobalVariable *G) { // If a global variable does not have dynamic initialization we don't // have to instrument it. However, if a global does not have initializer // at all, we assume it has dynamic initializer (in other TU). + // + // FIXME: Metadata should be attched directly to the global directly instead + // of being added to llvm.asan.globals. return G->hasInitializer() && !GlobalsMD.get(G).IsDynInit; } @@ -1612,7 +1711,7 @@ void AddressSanitizer::instrumentUnusualSizeOrAlignment( } } -void AddressSanitizerModule::poisonOneInitializer(Function &GlobalInit, +void ModuleAddressSanitizer::poisonOneInitializer(Function &GlobalInit, GlobalValue *ModuleName) { // Set up the arguments to our poison/unpoison functions. IRBuilder<> IRB(&GlobalInit.front(), @@ -1628,7 +1727,7 @@ void AddressSanitizerModule::poisonOneInitializer(Function &GlobalInit, CallInst::Create(AsanUnpoisonGlobals, "", RI); } -void AddressSanitizerModule::createInitializerPoisonCalls( +void ModuleAddressSanitizer::createInitializerPoisonCalls( Module &M, GlobalValue *ModuleName) { GlobalVariable *GV = M.getGlobalVariable("llvm.global_ctors"); if (!GV) @@ -1653,10 +1752,12 @@ void AddressSanitizerModule::createInitializerPoisonCalls( } } -bool AddressSanitizerModule::ShouldInstrumentGlobal(GlobalVariable *G) { +bool ModuleAddressSanitizer::ShouldInstrumentGlobal(GlobalVariable *G) { Type *Ty = G->getValueType(); LLVM_DEBUG(dbgs() << "GLOBAL: " << *G << "\n"); + // FIXME: Metadata should be attched directly to the global directly instead + // of being added to llvm.asan.globals. if (GlobalsMD.get(G).IsBlacklisted) return false; if (!Ty->isSized()) return false; if (!G->hasInitializer()) return false; @@ -1768,7 +1869,7 @@ bool AddressSanitizerModule::ShouldInstrumentGlobal(GlobalVariable *G) { // On Mach-O platforms, we emit global metadata in a separate section of the // binary in order to allow the linker to properly dead strip. This is only // supported on recent versions of ld64. -bool AddressSanitizerModule::ShouldUseMachOGlobalsSection() const { +bool ModuleAddressSanitizer::ShouldUseMachOGlobalsSection() const { if (!TargetTriple.isOSBinFormatMachO()) return false; @@ -1782,7 +1883,7 @@ bool AddressSanitizerModule::ShouldUseMachOGlobalsSection() const { return false; } -StringRef AddressSanitizerModule::getGlobalMetadataSection() const { +StringRef ModuleAddressSanitizer::getGlobalMetadataSection() const { switch (TargetTriple.getObjectFormat()) { case Triple::COFF: return ".ASAN$GL"; case Triple::ELF: return "asan_globals"; @@ -1792,7 +1893,7 @@ StringRef AddressSanitizerModule::getGlobalMetadataSection() const { llvm_unreachable("unsupported object format"); } -void AddressSanitizerModule::initializeCallbacks(Module &M) { +void ModuleAddressSanitizer::initializeCallbacks(Module &M) { IRBuilder<> IRB(*C); // Declare our poisoning and unpoisoning functions. @@ -1824,7 +1925,7 @@ void AddressSanitizerModule::initializeCallbacks(Module &M) { // Put the metadata and the instrumented global in the same group. This ensures // that the metadata is discarded if the instrumented global is discarded. -void AddressSanitizerModule::SetComdatForGlobalMetadata( +void ModuleAddressSanitizer::SetComdatForGlobalMetadata( GlobalVariable *G, GlobalVariable *Metadata, StringRef InternalSuffix) { Module &M = *G->getParent(); Comdat *C = G->getComdat(); @@ -1862,7 +1963,7 @@ void AddressSanitizerModule::SetComdatForGlobalMetadata( // Create a separate metadata global and put it in the appropriate ASan // global registration section. GlobalVariable * -AddressSanitizerModule::CreateMetadataGlobal(Module &M, Constant *Initializer, +ModuleAddressSanitizer::CreateMetadataGlobal(Module &M, Constant *Initializer, StringRef OriginalName) { auto Linkage = TargetTriple.isOSBinFormatMachO() ? GlobalVariable::InternalLinkage @@ -1874,7 +1975,7 @@ AddressSanitizerModule::CreateMetadataGlobal(Module &M, Constant *Initializer, return Metadata; } -IRBuilder<> AddressSanitizerModule::CreateAsanModuleDtor(Module &M) { +IRBuilder<> ModuleAddressSanitizer::CreateAsanModuleDtor(Module &M) { AsanDtorFunction = Function::Create(FunctionType::get(Type::getVoidTy(*C), false), GlobalValue::InternalLinkage, kAsanModuleDtorName, &M); @@ -1883,7 +1984,7 @@ IRBuilder<> AddressSanitizerModule::CreateAsanModuleDtor(Module &M) { return IRBuilder<>(ReturnInst::Create(*C, AsanDtorBB)); } -void AddressSanitizerModule::InstrumentGlobalsCOFF( +void ModuleAddressSanitizer::InstrumentGlobalsCOFF( IRBuilder<> &IRB, Module &M, ArrayRef ExtendedGlobals, ArrayRef MetadataInitializers) { assert(ExtendedGlobals.size() == MetadataInitializers.size()); @@ -1907,7 +2008,7 @@ void AddressSanitizerModule::InstrumentGlobalsCOFF( } } -void AddressSanitizerModule::InstrumentGlobalsELF( +void ModuleAddressSanitizer::InstrumentGlobalsELF( IRBuilder<> &IRB, Module &M, ArrayRef ExtendedGlobals, ArrayRef MetadataInitializers, const std::string &UniqueModuleId) { @@ -1966,7 +2067,7 @@ void AddressSanitizerModule::InstrumentGlobalsELF( IRB.CreatePointerCast(StopELFMetadata, IntptrTy)}); } -void AddressSanitizerModule::InstrumentGlobalsMachO( +void ModuleAddressSanitizer::InstrumentGlobalsMachO( IRBuilder<> &IRB, Module &M, ArrayRef ExtendedGlobals, ArrayRef MetadataInitializers) { assert(ExtendedGlobals.size() == MetadataInitializers.size()); @@ -2023,7 +2124,7 @@ void AddressSanitizerModule::InstrumentGlobalsMachO( {IRB.CreatePointerCast(RegisteredFlag, IntptrTy)}); } -void AddressSanitizerModule::InstrumentGlobalsWithMetadataArray( +void ModuleAddressSanitizer::InstrumentGlobalsWithMetadataArray( IRBuilder<> &IRB, Module &M, ArrayRef ExtendedGlobals, ArrayRef MetadataInitializers) { assert(ExtendedGlobals.size() == MetadataInitializers.size()); @@ -2057,9 +2158,9 @@ void AddressSanitizerModule::InstrumentGlobalsWithMetadataArray( // redzones and inserts this function into llvm.global_ctors. // Sets *CtorComdat to true if the global registration code emitted into the // asan constructor is comdat-compatible. -bool AddressSanitizerModule::InstrumentGlobals(IRBuilder<> &IRB, Module &M, bool *CtorComdat) { +bool ModuleAddressSanitizer::InstrumentGlobals(IRBuilder<> &IRB, Module &M, + bool *CtorComdat) { *CtorComdat = false; - GlobalsMD.init(M); SmallVector GlobalsToChange; @@ -2102,6 +2203,8 @@ bool AddressSanitizerModule::InstrumentGlobals(IRBuilder<> &IRB, Module &M, bool static const uint64_t kMaxGlobalRedzone = 1 << 18; GlobalVariable *G = GlobalsToChange[i]; + // FIXME: Metadata should be attched directly to the global directly instead + // of being added to llvm.asan.globals. auto MD = GlobalsMD.get(G); StringRef NameForGlobal = G->getName(); // Create string holding the global name (use global name from metadata @@ -2258,7 +2361,7 @@ bool AddressSanitizerModule::InstrumentGlobals(IRBuilder<> &IRB, Module &M, bool return true; } -int AddressSanitizerModule::GetAsanVersion(const Module &M) const { +int ModuleAddressSanitizer::GetAsanVersion(const Module &M) const { int LongSize = M.getDataLayout().getPointerSizeInBits(); bool isAndroid = Triple(M.getTargetTriple()).isAndroid(); int Version = 8; @@ -2268,12 +2371,7 @@ int AddressSanitizerModule::GetAsanVersion(const Module &M) const { return Version; } -bool AddressSanitizerModule::runOnModule(Module &M) { - C = &(M.getContext()); - int LongSize = M.getDataLayout().getPointerSizeInBits(); - IntptrTy = Type::getIntNTy(*C, LongSize); - TargetTriple = Triple(M.getTargetTriple()); - Mapping = getShadowMapping(TargetTriple, LongSize, CompileKernel); +bool ModuleAddressSanitizer::instrumentModule(Module &M) { initializeCallbacks(M); if (CompileKernel) @@ -2385,25 +2483,6 @@ void AddressSanitizer::initializeCallbacks(Module &M) { ArrayType::get(IRB.getInt8Ty(), 0)); } -// virtual -bool AddressSanitizer::doInitialization(Module &M) { - // Initialize the private fields. No one has accessed them before. - GlobalsMD.init(M); - - C = &(M.getContext()); - LongSize = M.getDataLayout().getPointerSizeInBits(); - IntptrTy = Type::getIntNTy(*C, LongSize); - TargetTriple = Triple(M.getTargetTriple()); - - Mapping = getShadowMapping(TargetTriple, LongSize, CompileKernel); - return true; -} - -bool AddressSanitizer::doFinalization(Module &M) { - GlobalsMD.reset(); - return false; -} - bool AddressSanitizer::maybeInsertAsanInitAtFunctionEntry(Function &F) { // For each NSObject descendant having a +load method, this method is invoked // by the ObjC runtime before any of the static constructors is called. @@ -2477,7 +2556,8 @@ void AddressSanitizer::markEscapedLocalAllocas(Function &F) { } } -bool AddressSanitizer::runOnFunction(Function &F) { +bool AddressSanitizer::instrumentFunction(Function &F, + const TargetLibraryInfo *TLI) { if (F.getLinkage() == GlobalValue::AvailableExternallyLinkage) return false; if (!ClDebugFunc.empty() && ClDebugFunc == F.getName()) return false; if (F.getName().startswith("__asan_")) return false; @@ -2496,7 +2576,6 @@ bool AddressSanitizer::runOnFunction(Function &F) { LLVM_DEBUG(dbgs() << "ASAN instrumenting:\n" << F << "\n"); initializeCallbacks(*F.getParent()); - DT = &getAnalysis().getDomTree(); FunctionStateRAII CleanupObj(this); @@ -2517,8 +2596,6 @@ bool AddressSanitizer::runOnFunction(Function &F) { bool IsWrite; unsigned Alignment; uint64_t TypeSize; - const TargetLibraryInfo *TLI = - &getAnalysis().getTLI(); // Fill the set of memory operations to instrument. for (auto &BB : F) { diff --git a/lib/Transforms/Instrumentation/Instrumentation.cpp b/lib/Transforms/Instrumentation/Instrumentation.cpp index 2f73bb2b0c0..40b0a4acac8 100644 --- a/lib/Transforms/Instrumentation/Instrumentation.cpp +++ b/lib/Transforms/Instrumentation/Instrumentation.cpp @@ -100,8 +100,8 @@ Comdat *llvm::GetOrCreateFunctionComdat(Function &F, Triple &T, /// initializeInstrumentation - Initialize all passes in the TransformUtils /// library. void llvm::initializeInstrumentation(PassRegistry &Registry) { - initializeAddressSanitizerPass(Registry); - initializeAddressSanitizerModulePass(Registry); + initializeAddressSanitizerLegacyPassPass(Registry); + initializeModuleAddressSanitizerLegacyPassPass(Registry); initializeBoundsCheckingLegacyPassPass(Registry); initializeControlHeightReductionLegacyPassPass(Registry); initializeGCOVProfilerLegacyPassPass(Registry); diff --git a/test/Instrumentation/AddressSanitizer/basic.ll b/test/Instrumentation/AddressSanitizer/basic.ll index 099965348eb..6397338344d 100644 --- a/test/Instrumentation/AddressSanitizer/basic.ll +++ b/test/Instrumentation/AddressSanitizer/basic.ll @@ -3,6 +3,10 @@ ; RUN: opt < %s -asan -asan-module -S | FileCheck --check-prefixes=CHECK,CHECK-S3 %s ; RUN: opt < %s -asan -asan-module -asan-mapping-scale=5 -S | FileCheck --check-prefixes=CHECK,CHECK-S5 %s +; We need the requires since both asan and asan-module require reading module level metadata which is done once by the asan-globals-md analysis +; RUN: opt < %s -passes='require,function(asan),module(asan-module)' -S | FileCheck --check-prefixes=CHECK,CHECK-S3 %s +; RUN: opt < %s -passes='require,function(asan),module(asan-module)' -asan-mapping-scale=5 -S | FileCheck --check-prefixes=CHECK,CHECK-S5 %s + target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" target triple = "x86_64-unknown-linux-gnu" ; CHECK: @llvm.global_ctors = {{.*}}@asan.module_ctor