diff --git a/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizer.h b/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizer.h --- a/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizer.h +++ b/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizer.h @@ -17,6 +17,7 @@ #include "llvm/IR/Function.h" #include "llvm/IR/Module.h" #include "llvm/IR/PassManager.h" +#include "llvm/Transforms/Instrumentation/AddressSanitizerOptions.h" namespace llvm { @@ -118,10 +119,10 @@ class ModuleAddressSanitizerPass : public PassInfoMixin { public: - explicit ModuleAddressSanitizerPass(bool CompileKernel = false, - bool Recover = false, - bool UseGlobalGC = true, - bool UseOdrIndicator = false); + explicit ModuleAddressSanitizerPass( + bool CompileKernel = false, bool Recover = false, bool UseGlobalGC = true, + bool UseOdrIndicator = false, + AsanDtorKind DestructorKind = AsanDtorKind::Global); PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); static bool isRequired() { return true; } @@ -130,6 +131,7 @@ bool Recover; bool UseGlobalGC; bool UseOdrIndicator; + AsanDtorKind DestructorKind; }; // Insert AddressSanitizer (address sanity checking) instrumentation @@ -138,7 +140,8 @@ bool UseAfterScope = false); ModulePass *createModuleAddressSanitizerLegacyPassPass( bool CompileKernel = false, bool Recover = false, bool UseGlobalsGC = true, - bool UseOdrIndicator = true); + bool UseOdrIndicator = true, + AsanDtorKind DestructorKind = AsanDtorKind::Global); } // namespace llvm diff --git a/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizerOptions.h b/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizerOptions.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizerOptions.h @@ -0,0 +1,25 @@ +//===--------- Definition of the AddressSanitizer options -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// This file defines data types used to set Address Sanitizer options. +//===----------------------------------------------------------------------===// +#ifndef LLVM_TRANSFORMS_INSTRUMENTATION_ADDRESSSANITIZER_OPTIONS_H +#define LLVM_TRANSFORMS_INSTRUMENTATION_ADDRESSSANITIZER_OPTIONS_H +#include "llvm/ADT/StringRef.h" + +namespace llvm { + +/// Types of ASan module destructors supported +enum class AsanDtorKind { + None, ///< Do not emit any destructors for ASan + Global, ///< Append to llvm.global_dtors + Invalid, ///< Not a valid destructor Kind. + // TODO(dliew): Add more more kinds. +}; +} // namespace llvm +#endif diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp --- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -383,6 +383,15 @@ cl::desc("Place ASan constructors in comdat sections"), cl::Hidden, cl::init(true)); +static cl::opt ClOverrideDestructorKind( + "asan-destructor-kind", + cl::desc("Sets the ASan destructor kind. The default is to use the value " + "provided to the pass constructor"), + cl::values(clEnumValN(AsanDtorKind::None, "none", "No destructors"), + clEnumValN(AsanDtorKind::Global, "global", + "Use global destructors")), + cl::init(AsanDtorKind::Invalid), cl::Hidden); + // Debug flags. static cl::opt ClDebug("asan-debug", cl::desc("debug"), cl::Hidden, @@ -741,7 +750,8 @@ public: ModuleAddressSanitizer(Module &M, const GlobalsMetadata *GlobalsMD, bool CompileKernel = false, bool Recover = false, - bool UseGlobalsGC = true, bool UseOdrIndicator = false) + bool UseGlobalsGC = true, bool UseOdrIndicator = false, + AsanDtorKind DestructorKind = AsanDtorKind::Global) : GlobalsMD(*GlobalsMD), CompileKernel(ClEnableKasan.getNumOccurrences() > 0 ? ClEnableKasan : CompileKernel), @@ -757,12 +767,17 @@ // argument is designed as workaround. Therefore, disable both // ClWithComdat and ClUseGlobalsGC unless the frontend says it's ok to // do globals-gc. - UseCtorComdat(UseGlobalsGC && ClWithComdat && !this->CompileKernel) { + UseCtorComdat(UseGlobalsGC && ClWithComdat && !this->CompileKernel), + DestructorKind(DestructorKind) { C = &(M.getContext()); int LongSize = M.getDataLayout().getPointerSizeInBits(); IntptrTy = Type::getIntNTy(*C, LongSize); TargetTriple = Triple(M.getTargetTriple()); Mapping = getShadowMapping(TargetTriple, LongSize, this->CompileKernel); + + if (ClOverrideDestructorKind != AsanDtorKind::Invalid) + this->DestructorKind = ClOverrideDestructorKind; + assert(this->DestructorKind != AsanDtorKind::Invalid); } bool instrumentModule(Module &); @@ -811,6 +826,7 @@ bool UsePrivateAlias; bool UseOdrIndicator; bool UseCtorComdat; + AsanDtorKind DestructorKind; Type *IntptrTy; LLVMContext *C; Triple TargetTriple; @@ -832,12 +848,13 @@ public: static char ID; - explicit ModuleAddressSanitizerLegacyPass(bool CompileKernel = false, - bool Recover = false, - bool UseGlobalGC = true, - bool UseOdrIndicator = false) + explicit ModuleAddressSanitizerLegacyPass( + bool CompileKernel = false, bool Recover = false, bool UseGlobalGC = true, + bool UseOdrIndicator = false, + AsanDtorKind DestructorKind = AsanDtorKind::Global) : ModulePass(ID), CompileKernel(CompileKernel), Recover(Recover), - UseGlobalGC(UseGlobalGC), UseOdrIndicator(UseOdrIndicator) { + UseGlobalGC(UseGlobalGC), UseOdrIndicator(UseOdrIndicator), + DestructorKind(DestructorKind) { initializeModuleAddressSanitizerLegacyPassPass( *PassRegistry::getPassRegistry()); } @@ -852,7 +869,8 @@ GlobalsMetadata &GlobalsMD = getAnalysis().getGlobalsMD(); ModuleAddressSanitizer ASanModule(M, &GlobalsMD, CompileKernel, Recover, - UseGlobalGC, UseOdrIndicator); + UseGlobalGC, UseOdrIndicator, + DestructorKind); return ASanModule.instrumentModule(M); } @@ -861,6 +879,7 @@ bool Recover; bool UseGlobalGC; bool UseOdrIndicator; + AsanDtorKind DestructorKind; }; // Stack poisoning does not play well with exception handling. @@ -1186,18 +1205,18 @@ return PreservedAnalyses::all(); } -ModuleAddressSanitizerPass::ModuleAddressSanitizerPass(bool CompileKernel, - bool Recover, - bool UseGlobalGC, - bool UseOdrIndicator) +ModuleAddressSanitizerPass::ModuleAddressSanitizerPass( + bool CompileKernel, bool Recover, bool UseGlobalGC, bool UseOdrIndicator, + AsanDtorKind DestructorKind) : CompileKernel(CompileKernel), Recover(Recover), UseGlobalGC(UseGlobalGC), - UseOdrIndicator(UseOdrIndicator) {} + UseOdrIndicator(UseOdrIndicator), DestructorKind(DestructorKind) {} PreservedAnalyses ModuleAddressSanitizerPass::run(Module &M, AnalysisManager &AM) { GlobalsMetadata &GlobalsMD = AM.getResult(M); ModuleAddressSanitizer Sanitizer(M, &GlobalsMD, CompileKernel, Recover, - UseGlobalGC, UseOdrIndicator); + UseGlobalGC, UseOdrIndicator, + DestructorKind); if (Sanitizer.instrumentModule(M)) return PreservedAnalyses::none(); return PreservedAnalyses::all(); @@ -1237,10 +1256,11 @@ false, false) ModulePass *llvm::createModuleAddressSanitizerLegacyPassPass( - bool CompileKernel, bool Recover, bool UseGlobalsGC, bool UseOdrIndicator) { + bool CompileKernel, bool Recover, bool UseGlobalsGC, bool UseOdrIndicator, + AsanDtorKind Destructor) { assert(!CompileKernel || Recover); - return new ModuleAddressSanitizerLegacyPass(CompileKernel, Recover, - UseGlobalsGC, UseOdrIndicator); + return new ModuleAddressSanitizerLegacyPass( + CompileKernel, Recover, UseGlobalsGC, UseOdrIndicator, Destructor); } static size_t TypeSizeToSizeIndex(uint32_t TypeSize) { @@ -2151,11 +2171,13 @@ // We also need to unregister globals at the end, e.g., when a shared library // gets closed. - IRBuilder<> IRB_Dtor(CreateAsanModuleDtor(M)); - IRB_Dtor.CreateCall(AsanUnregisterElfGlobals, - {IRB.CreatePointerCast(RegisteredFlag, IntptrTy), - IRB.CreatePointerCast(StartELFMetadata, IntptrTy), - IRB.CreatePointerCast(StopELFMetadata, IntptrTy)}); + if (DestructorKind != AsanDtorKind::None) { + IRBuilder<> IRB_Dtor(CreateAsanModuleDtor(M)); + IRB_Dtor.CreateCall(AsanUnregisterElfGlobals, + {IRB.CreatePointerCast(RegisteredFlag, IntptrTy), + IRB.CreatePointerCast(StartELFMetadata, IntptrTy), + IRB.CreatePointerCast(StopELFMetadata, IntptrTy)}); + } } void ModuleAddressSanitizer::InstrumentGlobalsMachO( @@ -2210,9 +2232,11 @@ // We also need to unregister globals at the end, e.g., when a shared library // gets closed. - IRBuilder<> IRB_Dtor(CreateAsanModuleDtor(M)); - IRB_Dtor.CreateCall(AsanUnregisterImageGlobals, - {IRB.CreatePointerCast(RegisteredFlag, IntptrTy)}); + if (DestructorKind != AsanDtorKind::None) { + IRBuilder<> IRB_Dtor(CreateAsanModuleDtor(M)); + IRB_Dtor.CreateCall(AsanUnregisterImageGlobals, + {IRB.CreatePointerCast(RegisteredFlag, IntptrTy)}); + } } void ModuleAddressSanitizer::InstrumentGlobalsWithMetadataArray( @@ -2238,10 +2262,12 @@ // We also need to unregister globals at the end, e.g., when a shared library // gets closed. - IRBuilder<> IRB_Dtor(CreateAsanModuleDtor(M)); - IRB_Dtor.CreateCall(AsanUnregisterGlobals, - {IRB.CreatePointerCast(AllGlobals, IntptrTy), - ConstantInt::get(IntptrTy, N)}); + if (DestructorKind != AsanDtorKind::None) { + IRBuilder<> IRB_Dtor(CreateAsanModuleDtor(M)); + IRB_Dtor.CreateCall(AsanUnregisterGlobals, + {IRB.CreatePointerCast(AllGlobals, IntptrTy), + ConstantInt::get(IntptrTy, N)}); + } } // This function replaces all global variables with new variables that have diff --git a/llvm/test/Instrumentation/AddressSanitizer/no_global_dtors.ll b/llvm/test/Instrumentation/AddressSanitizer/no_global_dtors.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Instrumentation/AddressSanitizer/no_global_dtors.ll @@ -0,0 +1,22 @@ +; Check Default behaviour still emits dtors +; RUN: opt < %s -asan -asan-module -enable-new-pm=0 -S | \ +; RUN: FileCheck -check-prefix=CHECK-DEFAULT %s +; RUN: opt < %s -passes='asan-pipeline' -S | \ +; RUN: FileCheck -check-prefix=CHECK-DEFAULT %s +; CHECK-DEFAULT: llvm.global_dtor{{.+}}asan.module_dtor +; CHECK-DEFAULT: define internal void @asan.module_dtor + +; Check with dtor emission disabled +; RUN: opt < %s -asan -asan-module -enable-new-pm=0 \ +; RUN: -asan-destructor-kind=none -S | \ +; RUN: FileCheck %s +; RUN: opt < %s -passes='asan-pipeline' \ +; RUN: -asan-destructor-kind=none -S | \ +; RUN: FileCheck %s +; CHECK-NOT: llvm.global_dtor{{.+}}asan.module_dtor +; CHECK-NOT: define internal void @asan.module_dtor + +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