From 2b02df781928897beb640df24078dc3c4eb2eb14 Mon Sep 17 00:00:00 2001 From: usama hameed Date: Tue, 24 Jan 2023 14:03:26 -0800 Subject: [PATCH] [ASan] Introduce a flag -asan-constructor-kind to control the generation of the Asan module constructor. By default, ASan generates an asan.module_ctor function that initializes asan and registers the globals in the module. This function is added to the @llvm.global_ctors array. Previously, there was no way to control the generation of this function. This patch adds a way to control the generation of this function. The flag -asan-constructor-kind has two options: global: This is the default option and the default behavior of ASan. It generates an asan.module_ctor function. none: This skips the generation of the asan.module_ctor function. rdar://104448572 Differential revision: https://reviews.llvm.org/D142505 --- .../Transforms/Instrumentation/AddressSanitizer.h | 4 +- .../Instrumentation/AddressSanitizerOptions.h | 6 ++ .../Instrumentation/AddressSanitizer.cpp | 77 +++++++++++++++------- .../AddressSanitizer/no-global-ctors.ll | 17 +++++ 4 files changed, 78 insertions(+), 26 deletions(-) create mode 100644 llvm/test/Instrumentation/AddressSanitizer/no-global-ctors.ll diff --git a/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizer.h b/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizer.h index 41ca345..ca54387 100644 --- a/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizer.h +++ b/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizer.h @@ -37,7 +37,8 @@ class AddressSanitizerPass : public PassInfoMixin { public: AddressSanitizerPass(const AddressSanitizerOptions &Options, bool UseGlobalGC = true, bool UseOdrIndicator = true, - AsanDtorKind DestructorKind = AsanDtorKind::Global); + AsanDtorKind DestructorKind = AsanDtorKind::Global, + AsanCtorKind ConstructorKind = AsanCtorKind::Global); PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); void printPipeline(raw_ostream &OS, function_ref MapClassName2PassName); @@ -48,6 +49,7 @@ private: bool UseGlobalGC; bool UseOdrIndicator; AsanDtorKind DestructorKind; + AsanCtorKind ConstructorKind; }; struct ASanAccessInfo { diff --git a/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizerOptions.h b/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizerOptions.h index 187aaed..d697b72 100644 --- a/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizerOptions.h +++ b/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizerOptions.h @@ -19,6 +19,12 @@ enum class AsanDtorKind { Invalid, ///< Not a valid destructor Kind. }; +/// Types of ASan module constructors supported +enum class AsanCtorKind { + None, + Global +}; + /// Mode of ASan detect stack use after return enum class AsanDetectStackUseAfterReturnMode { Never, ///< Never detect stack use after return. diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp index d7bf846..599eeea 100644 --- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -349,6 +349,13 @@ static cl::opt ClSkipPromotableAllocas( cl::desc("Do not instrument promotable allocas"), cl::Hidden, cl::init(true)); +static cl::opt ClConstructorKind( + "asan-constructor-kind", + cl::desc("Sets the ASan constructor kind"), + cl::values(clEnumValN(AsanCtorKind::None, "none", "No constructors"), + clEnumValN(AsanCtorKind::Global, "global", + "Use global constructors")), + cl::init(AsanCtorKind::Global), cl::Hidden); // These flags allow to change the shadow mapping. // The shadow mapping looks like // Shadow = (Mem >> scale) + offset @@ -772,7 +779,8 @@ public: ModuleAddressSanitizer(Module &M, bool CompileKernel = false, bool Recover = false, bool UseGlobalsGC = true, bool UseOdrIndicator = true, - AsanDtorKind DestructorKind = AsanDtorKind::Global) + AsanDtorKind DestructorKind = AsanDtorKind::Global, + AsanCtorKind ConstructorKind = AsanCtorKind::Global) : CompileKernel(ClEnableKasan.getNumOccurrences() > 0 ? ClEnableKasan : CompileKernel), Recover(ClRecover.getNumOccurrences() > 0 ? ClRecover : Recover), @@ -792,7 +800,8 @@ public: // ClWithComdat and ClUseGlobalsGC unless the frontend says it's ok to // do globals-gc. UseCtorComdat(UseGlobalsGC && ClWithComdat && !this->CompileKernel), - DestructorKind(DestructorKind) { + DestructorKind(DestructorKind), + ConstructorKind(ConstructorKind) { C = &(M.getContext()); int LongSize = M.getDataLayout().getPointerSizeInBits(); IntptrTy = Type::getIntNTy(*C, LongSize); @@ -850,6 +859,7 @@ private: bool UseOdrIndicator; bool UseCtorComdat; AsanDtorKind DestructorKind; + AsanCtorKind ConstructorKind; Type *IntptrTy; LLVMContext *C; Triple TargetTriple; @@ -1131,15 +1141,18 @@ void AddressSanitizerPass::printPipeline( AddressSanitizerPass::AddressSanitizerPass( const AddressSanitizerOptions &Options, bool UseGlobalGC, - bool UseOdrIndicator, AsanDtorKind DestructorKind) + bool UseOdrIndicator, AsanDtorKind DestructorKind, + AsanCtorKind ConstructorKind) : Options(Options), UseGlobalGC(UseGlobalGC), - UseOdrIndicator(UseOdrIndicator), DestructorKind(DestructorKind) {} + UseOdrIndicator(UseOdrIndicator), DestructorKind(DestructorKind), + ConstructorKind(ClConstructorKind) {} PreservedAnalyses AddressSanitizerPass::run(Module &M, ModuleAnalysisManager &MAM) { ModuleAddressSanitizer ModuleSanitizer(M, Options.CompileKernel, Options.Recover, UseGlobalGC, - UseOdrIndicator, DestructorKind); + UseOdrIndicator, DestructorKind, + ConstructorKind); bool Modified = false; auto &FAM = MAM.getResult(M).getManager(); const StackSafetyGlobalInfo *const SSGI = @@ -2095,7 +2108,8 @@ void ModuleAddressSanitizer::InstrumentGlobalsELF( StopELFMetadata->setVisibility(GlobalVariable::HiddenVisibility); // Create a call to register the globals with the runtime. - IRB.CreateCall(AsanRegisterElfGlobals, + if (ConstructorKind == AsanCtorKind::Global) + IRB.CreateCall(AsanRegisterElfGlobals, {IRB.CreatePointerCast(RegisteredFlag, IntptrTy), IRB.CreatePointerCast(StartELFMetadata, IntptrTy), IRB.CreatePointerCast(StopELFMetadata, IntptrTy)}); @@ -2158,7 +2172,8 @@ void ModuleAddressSanitizer::InstrumentGlobalsMachO( ConstantInt::get(IntptrTy, 0), kAsanGlobalsRegisteredFlagName); RegisteredFlag->setVisibility(GlobalVariable::HiddenVisibility); - IRB.CreateCall(AsanRegisterImageGlobals, + if (ConstructorKind == AsanCtorKind::Global) + IRB.CreateCall(AsanRegisterImageGlobals, {IRB.CreatePointerCast(RegisteredFlag, IntptrTy)}); // We also need to unregister globals at the end, e.g., when a shared library @@ -2187,7 +2202,8 @@ void ModuleAddressSanitizer::InstrumentGlobalsWithMetadataArray( if (Mapping.Scale > 3) AllGlobals->setAlignment(Align(1ULL << Mapping.Scale)); - IRB.CreateCall(AsanRegisterGlobals, + if (ConstructorKind == AsanCtorKind::Global) + IRB.CreateCall(AsanRegisterGlobals, {IRB.CreatePointerCast(AllGlobals, IntptrTy), ConstantInt::get(IntptrTy, N)}); @@ -2443,24 +2459,32 @@ bool ModuleAddressSanitizer::instrumentModule(Module &M) { // Create a module constructor. A destructor is created lazily because not all // platforms, and not all modules need it. - if (CompileKernel) { - // The kernel always builds with its own runtime, and therefore does not - // need the init and version check calls. - AsanCtorFunction = createSanitizerCtor(M, kAsanModuleCtorName); - } else { - std::string AsanVersion = std::to_string(GetAsanVersion(M)); - std::string VersionCheckName = - ClInsertVersionCheck ? (kAsanVersionCheckNamePrefix + AsanVersion) : ""; - std::tie(AsanCtorFunction, std::ignore) = - createSanitizerCtorAndInitFunctions(M, kAsanModuleCtorName, - kAsanInitName, /*InitArgTypes=*/{}, - /*InitArgs=*/{}, VersionCheckName); + if (ConstructorKind == AsanCtorKind::Global) { + if (CompileKernel) { + // The kernel always builds with its own runtime, and therefore does not + // need the init and version check calls. + AsanCtorFunction = createSanitizerCtor(M, kAsanModuleCtorName); + } else { + std::string AsanVersion = std::to_string(GetAsanVersion(M)); + std::string VersionCheckName = + ClInsertVersionCheck ? (kAsanVersionCheckNamePrefix + AsanVersion) : ""; + std::tie(AsanCtorFunction, std::ignore) = + createSanitizerCtorAndInitFunctions(M, kAsanModuleCtorName, + kAsanInitName, /*InitArgTypes=*/{}, + /*InitArgs=*/{}, VersionCheckName); + } } bool CtorComdat = true; if (ClGlobals) { - IRBuilder<> IRB(AsanCtorFunction->getEntryBlock().getTerminator()); - InstrumentGlobals(IRB, M, &CtorComdat); + assert(AsanCtorFunction || ConstructorKind == AsanCtorKind::None); + if (AsanCtorFunction) { + IRBuilder<> IRB(AsanCtorFunction->getEntryBlock().getTerminator()); + InstrumentGlobals(IRB, M, &CtorComdat); + } else { + IRBuilder<> IRB(*C); + InstrumentGlobals(IRB, M, &CtorComdat); + } } const uint64_t Priority = GetCtorAndDtorPriority(TargetTriple); @@ -2469,14 +2493,17 @@ bool ModuleAddressSanitizer::instrumentModule(Module &M) { // (1) global instrumentation is not TU-specific // (2) target is ELF. if (UseCtorComdat && TargetTriple.isOSBinFormatELF() && CtorComdat) { - AsanCtorFunction->setComdat(M.getOrInsertComdat(kAsanModuleCtorName)); - appendToGlobalCtors(M, AsanCtorFunction, Priority, AsanCtorFunction); + if (AsanCtorFunction) { + AsanCtorFunction->setComdat(M.getOrInsertComdat(kAsanModuleCtorName)); + appendToGlobalCtors(M, AsanCtorFunction, Priority, AsanCtorFunction); + } if (AsanDtorFunction) { AsanDtorFunction->setComdat(M.getOrInsertComdat(kAsanModuleDtorName)); appendToGlobalDtors(M, AsanDtorFunction, Priority, AsanDtorFunction); } } else { - appendToGlobalCtors(M, AsanCtorFunction, Priority); + if (AsanCtorFunction) + appendToGlobalCtors(M, AsanCtorFunction, Priority); if (AsanDtorFunction) appendToGlobalDtors(M, AsanDtorFunction, Priority); } diff --git a/llvm/test/Instrumentation/AddressSanitizer/no-global-ctors.ll b/llvm/test/Instrumentation/AddressSanitizer/no-global-ctors.ll new file mode 100644 index 0000000..79ed0b7 --- /dev/null +++ b/llvm/test/Instrumentation/AddressSanitizer/no-global-ctors.ll @@ -0,0 +1,17 @@ +; Check Default behaviour still emits ctors +; RUN: opt < %s -passes=asan -S | \ +; RUN: FileCheck -check-prefix=CHECK-DEFAULT %s +; CHECK-DEFAULT: llvm.global_ctor{{.+}}asan.module_ctor +; CHECK-DEFAULT: define internal void @asan.module_ctor + +; Check with ctor emission disabled +; RUN: opt < %s -passes=asan \ +; RUN: -asan-constructor-kind=none -S | \ +; RUN: FileCheck %s +; CHECK-NOT: llvm.global_ctor{{.+}}asan.module_ctor +; CHECK-NOT: define internal void @asan.module_ctor + +target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx11.0.0" + +@foo = dso_local global i32 0, align 4 -- 2.7.4