Index: include/llvm/IR/AddressSanitizerPass.h =================================================================== --- /dev/null +++ include/llvm/IR/AddressSanitizerPass.h @@ -0,0 +1,53 @@ +//===--------- 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_IR_ADDRESSSANITIZERNEWPASS_H +#define LLVM_IR_ADDRESSSANITIZERNEWPASS_H + +#include "llvm/Analysis/InstructionSimplify.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Module.h" + +namespace llvm { + +struct FunctionStackPoisoner; +struct AddressSanitizer; +class AddressSanitizerModule; + +class AddressSanitizerPass { +public: + explicit AddressSanitizerPass(bool CompileKernel = false, + bool Recover = false, + bool UseAfterScope = false); + PreservedAnalyses run(Function &F, AnalysisManager &AM); + static StringRef name() { return "AddressSanitizerFunctionPass"; } + +private: + AddressSanitizer *Sanitizer; +}; + +class AddressSanitizerModulePass { +public: + explicit AddressSanitizerModulePass(bool CompileKernel = false, + bool Recover = false, + bool UseAfterScope = true); + PreservedAnalyses run(Module &M, AnalysisManager &AM); + static StringRef name() { return "AddressSanitizerModule"; } + +private: + AddressSanitizerModule *Sanitizer; +}; + +} // namespace llvm + +#endif Index: include/llvm/InitializePasses.h =================================================================== --- include/llvm/InitializePasses.h +++ include/llvm/InitializePasses.h @@ -65,8 +65,8 @@ void initializeAAResultsWrapperPassPass(PassRegistry&); void initializeADCELegacyPassPass(PassRegistry&); void initializeAddDiscriminatorsLegacyPassPass(PassRegistry&); -void initializeAddressSanitizerModulePass(PassRegistry&); -void initializeAddressSanitizerPass(PassRegistry&); +void initializeAddressSanitizerModuleLegacyPass(PassRegistry &); +void initializeAddressSanitizerLegacyPass(PassRegistry &); void initializeAggressiveInstCombinerLegacyPassPass(PassRegistry&); void initializeAliasSetPrinterPass(PassRegistry&); void initializeAlignmentFromAssumptionsPass(PassRegistry&); Index: lib/Passes/PassBuilder.cpp =================================================================== --- lib/Passes/PassBuilder.cpp +++ lib/Passes/PassBuilder.cpp @@ -53,6 +53,7 @@ #include "llvm/Analysis/TypeBasedAliasAnalysis.h" #include "llvm/CodeGen/PreISelIntrinsicLowering.h" #include "llvm/CodeGen/UnreachableBlockElim.h" +#include "llvm/IR/AddressSanitizerPass.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/IRPrintingPasses.h" #include "llvm/IR/PassManager.h" Index: lib/Passes/PassRegistry.def =================================================================== --- lib/Passes/PassRegistry.def +++ lib/Passes/PassRegistry.def @@ -40,6 +40,7 @@ #define MODULE_PASS(NAME, CREATE_PASS) #endif MODULE_PASS("always-inline", AlwaysInlinerPass()) +MODULE_PASS("asan-module", AddressSanitizerModulePass()) MODULE_PASS("called-value-propagation", CalledValuePropagationPass()) MODULE_PASS("cg-profile", CGProfilePass()) MODULE_PASS("constmerge", ConstantMergePass()) @@ -146,6 +147,7 @@ FUNCTION_PASS("add-discriminators", AddDiscriminatorsPass()) FUNCTION_PASS("aggressive-instcombine", AggressiveInstCombinePass()) FUNCTION_PASS("alignment-from-assumptions", AlignmentFromAssumptionsPass()) +FUNCTION_PASS("asan", AddressSanitizerPass()) FUNCTION_PASS("bdce", BDCEPass()) FUNCTION_PASS("bounds-checking", BoundsCheckingPass()) FUNCTION_PASS("break-crit-edges", BreakCriticalEdgesPass()) Index: lib/Transforms/Instrumentation/AddressSanitizer.cpp =================================================================== --- lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -25,9 +25,9 @@ #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/AddressSanitizerPass.h" #include "llvm/IR/Argument.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/BasicBlock.h" @@ -72,6 +72,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 @@ -594,30 +595,17 @@ return std::max(32U, 1U << MappingScale); } -namespace { - /// AddressSanitizer: instrument the code in module to find memory bugs. -struct AddressSanitizer : public FunctionPass { - // Pass identification, replacement for typeid - static char ID; - +struct llvm::AddressSanitizer { explicit AddressSanitizer(bool CompileKernel = false, bool Recover = false, bool UseAfterScope = false) - : FunctionPass(ID), UseAfterScope(UseAfterScope || ClUseAfterScope) { + : UseAfterScope(UseAfterScope || ClUseAfterScope) { this->Recover = ClRecover.getNumOccurrences() > 0 ? ClRecover : Recover; this->CompileKernel = ClEnableKasan.getNumOccurrences() > 0 ? ClEnableKasan : CompileKernel; - initializeAddressSanitizerPass(*PassRegistry::getPassRegistry()); } - StringRef getPassName() const override { - return "AddressSanitizerFunctionPass"; - } - - void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.addRequired(); - AU.addRequired(); - } + static StringRef getPassName() { return "AddressSanitizerFunctionPass"; } uint64_t getAllocaSizeInBytes(const AllocaInst &AI) const { uint64_t ArraySize = 1; @@ -661,12 +649,13 @@ Value *SizeArgument, uint32_t Exp); void instrumentMemIntrinsic(MemIntrinsic *MI); Value *memToShadow(Value *Shadow, IRBuilder<> &IRB); - bool runOnFunction(Function &F) override; bool maybeInsertAsanInitAtFunctionEntry(Function &F); void maybeInsertDynamicShadowAtFunctionEntry(Function &F); void markEscapedLocalAllocas(Function &F); - bool doInitialization(Module &M) override; - bool doFinalization(Module &M) override; + + /// Return true if the function changed. + bool instrument(Function &F, DominatorTree *DTree, + const TargetLibraryInfo *TLI); DominatorTree &getDominatorTree() const { return *DT; } @@ -722,18 +711,15 @@ Value *LocalDynamicShadow = nullptr; GlobalsMetadata GlobalsMD; DenseMap ProcessedAllocas; + bool Inited = false; }; -class AddressSanitizerModule : public ModulePass { +class llvm::AddressSanitizerModule { public: - // Pass identification, replacement for typeid - static char ID; - explicit AddressSanitizerModule(bool CompileKernel = false, bool Recover = false, bool UseGlobalsGC = true) - : ModulePass(ID), - UseGlobalsGC(UseGlobalsGC && ClUseGlobalsGC), + : UseGlobalsGC(UseGlobalsGC && ClUseGlobalsGC), // 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,14 +728,13 @@ // 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"; } + bool instrument(Module &M); + static StringRef name() { return "AddressSanitizerModule"; } private: void initializeCallbacks(Module &M); @@ -817,7 +802,7 @@ // compiler hoists the load of the shadow value somewhere too high. // This causes asan to report a non-existing bug on 453.povray. // It sounds like an LLVM bug. -struct FunctionStackPoisoner : public InstVisitor { +struct llvm::FunctionStackPoisoner : public InstVisitor { Function &F; AddressSanitizer &ASan; DIBuilder DIB; @@ -1057,18 +1042,89 @@ Instruction *ThenTerm, Value *ValueIfFalse); }; -} // end anonymous namespace +namespace { + +class AddressSanitizerLegacy : public FunctionPass { +public: + static char ID; + + explicit AddressSanitizerLegacy(bool CompileKernel = false, + bool Recover = false, + bool UseAfterScope = false) + : FunctionPass(ID), Sanitizer(CompileKernel, Recover, UseAfterScope) {} + + StringRef getPassName() const override { return Sanitizer.getPassName(); } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired(); + AU.addRequired(); + } + + bool runOnFunction(Function &F) override { + DominatorTree *DTree = + &getAnalysis().getDomTree(); + const TargetLibraryInfo *TLI = + &getAnalysis().getTLI(); + return Sanitizer.instrument(F, DTree, TLI); + } + +private: + AddressSanitizer Sanitizer; +}; + +class AddressSanitizerModuleLegacy : public ModulePass { +public: + static char ID; + + explicit AddressSanitizerModuleLegacy(bool CompileKernel = false, + bool Recover = false, + bool UseAfterScope = true) + : ModulePass(ID), Sanitizer(CompileKernel, Recover, UseAfterScope) {} + + StringRef getPassName() const override { return Sanitizer.name(); } + + bool runOnModule(Module &M) override { return Sanitizer.instrument(M); } + +private: + AddressSanitizerModule Sanitizer; +}; + +} // namespace + +AddressSanitizerPass::AddressSanitizerPass(bool CompileKernel, bool Recover, + bool UseAfterScope) + : Sanitizer(new AddressSanitizer(CompileKernel, Recover, UseAfterScope)) {} + +AddressSanitizerModulePass::AddressSanitizerModulePass(bool CompileKernel, + bool Recover, + bool UseAfterScope) + : Sanitizer( + new AddressSanitizerModule(CompileKernel, Recover, UseAfterScope)) {} + +PreservedAnalyses AddressSanitizerPass::run(Function &F, + AnalysisManager &AM) { + DominatorTree *DT = &AM.getResult(F); + const TargetLibraryInfo *TLI = &AM.getResult(F); + return Sanitizer->instrument(F, DT, TLI) ? PreservedAnalyses::none() + : PreservedAnalyses::all(); +} + +PreservedAnalyses AddressSanitizerModulePass::run(Module &M, + AnalysisManager &AM) { + return Sanitizer->instrument(M) ? PreservedAnalyses::none() + : PreservedAnalyses::all(); +} -char AddressSanitizer::ID = 0; +char AddressSanitizerLegacy::ID = 0; INITIALIZE_PASS_BEGIN( - AddressSanitizer, "asan", + AddressSanitizerLegacy, "asan", "AddressSanitizer: detects use-after-free and out-of-bounds bugs.", false, false) INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) INITIALIZE_PASS_END( - AddressSanitizer, "asan", + AddressSanitizerLegacy, "asan", "AddressSanitizer: detects use-after-free and out-of-bounds bugs.", false, false) @@ -1076,13 +1132,13 @@ bool Recover, bool UseAfterScope) { assert(!CompileKernel || Recover); - return new AddressSanitizer(CompileKernel, Recover, UseAfterScope); + return new AddressSanitizerLegacy(CompileKernel, Recover, UseAfterScope); } -char AddressSanitizerModule::ID = 0; +char AddressSanitizerModuleLegacy::ID = 0; INITIALIZE_PASS( - AddressSanitizerModule, "asan-module", + AddressSanitizerModuleLegacy, "asan-module", "AddressSanitizer: detects use-after-free and out-of-bounds bugs." "ModulePass", false, false) @@ -1091,7 +1147,7 @@ bool Recover, bool UseGlobalsGC) { assert(!CompileKernel || Recover); - return new AddressSanitizerModule(CompileKernel, Recover, UseGlobalsGC); + return new AddressSanitizerModuleLegacy(CompileKernel, Recover, UseGlobalsGC); } static size_t TypeSizeToSizeIndex(uint32_t TypeSize) { @@ -2268,7 +2324,7 @@ return Version; } -bool AddressSanitizerModule::runOnModule(Module &M) { +bool AddressSanitizerModule::instrument(Module &M) { C = &(M.getContext()); int LongSize = M.getDataLayout().getPointerSizeInBits(); IntptrTy = Type::getIntNTy(*C, LongSize); @@ -2387,25 +2443,6 @@ 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. @@ -2479,7 +2516,22 @@ } } -bool AddressSanitizer::runOnFunction(Function &F) { +bool AddressSanitizer::instrument(Function &F, DominatorTree *DTree, + const TargetLibraryInfo *TLI) { + if (!Inited) { + // Initialize the private fields. No one has accessed them before. + Module &M = *F.getParent(); + GlobalsMD.init(M); + + C = &(M.getContext()); + LongSize = M.getDataLayout().getPointerSizeInBits(); + IntptrTy = Type::getIntNTy(*C, LongSize); + TargetTriple = Triple(M.getTargetTriple()); + + Mapping = getShadowMapping(TargetTriple, LongSize, CompileKernel); + Inited = true; + } + if (F.getLinkage() == GlobalValue::AvailableExternallyLinkage) return false; if (!ClDebugFunc.empty() && ClDebugFunc == F.getName()) return false; if (F.getName().startswith("__asan_")) return false; @@ -2498,7 +2550,7 @@ LLVM_DEBUG(dbgs() << "ASAN instrumenting:\n" << F << "\n"); initializeCallbacks(*F.getParent()); - DT = &getAnalysis().getDomTree(); + DT = DTree; FunctionStateRAII CleanupObj(this); @@ -2519,8 +2571,6 @@ bool IsWrite; unsigned Alignment; uint64_t TypeSize; - const TargetLibraryInfo *TLI = - &getAnalysis().getTLI(); // Fill the set of memory operations to instrument. for (auto &BB : F) { Index: lib/Transforms/Instrumentation/Instrumentation.cpp =================================================================== --- lib/Transforms/Instrumentation/Instrumentation.cpp +++ lib/Transforms/Instrumentation/Instrumentation.cpp @@ -56,8 +56,8 @@ /// initializeInstrumentation - Initialize all passes in the TransformUtils /// library. void llvm::initializeInstrumentation(PassRegistry &Registry) { - initializeAddressSanitizerPass(Registry); - initializeAddressSanitizerModulePass(Registry); + initializeAddressSanitizerLegacyPass(Registry); + initializeAddressSanitizerModuleLegacyPass(Registry); initializeBoundsCheckingLegacyPassPass(Registry); initializeControlHeightReductionLegacyPassPass(Registry); initializeGCOVProfilerLegacyPassPass(Registry); Index: test/Instrumentation/AddressSanitizer/basic.ll =================================================================== --- test/Instrumentation/AddressSanitizer/basic.ll +++ test/Instrumentation/AddressSanitizer/basic.ll @@ -1,7 +1,9 @@ ; Test basic address sanitizer instrumentation. ; ; RUN: opt < %s -asan -asan-module -S | FileCheck --check-prefixes=CHECK,CHECK-S3 %s +; RUN: opt < %s -passes='function(asan),module(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 +; RUN: opt < %s -passes='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"