Skip to content

Commit

Permalink
[ASan] Introduce a way set different ways of emitting module destruct…
Browse files Browse the repository at this point in the history
…ors.

Previously there was no way to control how module destructors were emitted
by `ModuleAddressSanitizerPass`. However, we want language frontends (e.g. Clang)
to be able to decide how to emit these destructors (if at all).

This patch introduces the `AsanDtorKind` enum that represents the different ways
destructors can be emitted. There are currently only two valid ways to emit destructors.

* `Global` - Use `llvm.global_dtors`. This was the previous behavior and is the default.
* `None`   - Do not emit module destructors.

The `ModuleAddressSanitizerPass` and the various wrappers around it have been updated
to take the `AsanDtorKind` as an argument.

The `-asan-destructor-kind=` command line argument has been introduced to make this
easy to test from `opt`. If this argument is specified it overrides the value passed
to the `ModuleAddressSanitizerPass` constructor.

Note that `AsanDtorKind` is not `bool` because we will introduce a new way to
emit destructors in a subsequent patch.

Note that `AsanDtorKind` is given its own header file because if it is declared
in `Transforms/Instrumentation/AddressSanitizer.h` it leads to compile error
(Module is ambiguous) when trying to use it in
`clang/Basic/CodeGenOptions.def`.

rdar://71609176

Differential Revision: https://reviews.llvm.org/D96571
  • Loading branch information
danliew-apple committed Feb 24, 2021
1 parent a3ce7f5 commit 7d3ef10
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 34 deletions.
13 changes: 8 additions & 5 deletions llvm/include/llvm/Transforms/Instrumentation/AddressSanitizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -118,10 +119,10 @@ class AddressSanitizerPass : public PassInfoMixin<AddressSanitizerPass> {
class ModuleAddressSanitizerPass
: public PassInfoMixin<ModuleAddressSanitizerPass> {
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; }

Expand All @@ -130,6 +131,7 @@ class ModuleAddressSanitizerPass
bool Recover;
bool UseGlobalGC;
bool UseOdrIndicator;
AsanDtorKind DestructorKind;
};

// Insert AddressSanitizer (address sanity checking) instrumentation
Expand All @@ -138,7 +140,8 @@ FunctionPass *createAddressSanitizerFunctionPass(bool CompileKernel = false,
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

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//===--------- 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_ADDRESSSANITIZEROPTIONS_H
#define LLVM_TRANSFORMS_INSTRUMENTATION_ADDRESSSANITIZEROPTIONS_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
84 changes: 55 additions & 29 deletions llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,15 @@ static cl::opt<bool>
cl::desc("Place ASan constructors in comdat sections"),
cl::Hidden, cl::init(true));

static cl::opt<AsanDtorKind> 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<int> ClDebug("asan-debug", cl::desc("debug"), cl::Hidden,
Expand Down Expand Up @@ -741,7 +750,8 @@ class ModuleAddressSanitizer {
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),
Expand All @@ -757,12 +767,17 @@ class ModuleAddressSanitizer {
// 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 &);
Expand Down Expand Up @@ -811,6 +826,7 @@ class ModuleAddressSanitizer {
bool UsePrivateAlias;
bool UseOdrIndicator;
bool UseCtorComdat;
AsanDtorKind DestructorKind;
Type *IntptrTy;
LLVMContext *C;
Triple TargetTriple;
Expand All @@ -832,12 +848,13 @@ class ModuleAddressSanitizerLegacyPass : public ModulePass {
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());
}
Expand All @@ -852,7 +869,8 @@ class ModuleAddressSanitizerLegacyPass : public ModulePass {
GlobalsMetadata &GlobalsMD =
getAnalysis<ASanGlobalsMetadataWrapperPass>().getGlobalsMD();
ModuleAddressSanitizer ASanModule(M, &GlobalsMD, CompileKernel, Recover,
UseGlobalGC, UseOdrIndicator);
UseGlobalGC, UseOdrIndicator,
DestructorKind);
return ASanModule.instrumentModule(M);
}

Expand All @@ -861,6 +879,7 @@ class ModuleAddressSanitizerLegacyPass : public ModulePass {
bool Recover;
bool UseGlobalGC;
bool UseOdrIndicator;
AsanDtorKind DestructorKind;
};

// Stack poisoning does not play well with exception handling.
Expand Down Expand Up @@ -1186,18 +1205,18 @@ PreservedAnalyses AddressSanitizerPass::run(Function &F,
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<Module> &AM) {
GlobalsMetadata &GlobalsMD = AM.getResult<ASanGlobalsMetadataAnalysis>(M);
ModuleAddressSanitizer Sanitizer(M, &GlobalsMD, CompileKernel, Recover,
UseGlobalGC, UseOdrIndicator);
UseGlobalGC, UseOdrIndicator,
DestructorKind);
if (Sanitizer.instrumentModule(M))
return PreservedAnalyses::none();
return PreservedAnalyses::all();
Expand Down Expand Up @@ -1237,10 +1256,11 @@ INITIALIZE_PASS(
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) {
Expand Down Expand Up @@ -2151,11 +2171,13 @@ void ModuleAddressSanitizer::InstrumentGlobalsELF(

// 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<> IrbDtor(CreateAsanModuleDtor(M));
IrbDtor.CreateCall(AsanUnregisterElfGlobals,
{IRB.CreatePointerCast(RegisteredFlag, IntptrTy),
IRB.CreatePointerCast(StartELFMetadata, IntptrTy),
IRB.CreatePointerCast(StopELFMetadata, IntptrTy)});
}
}

void ModuleAddressSanitizer::InstrumentGlobalsMachO(
Expand Down Expand Up @@ -2210,9 +2232,11 @@ void ModuleAddressSanitizer::InstrumentGlobalsMachO(

// 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<> IrbDtor(CreateAsanModuleDtor(M));
IrbDtor.CreateCall(AsanUnregisterImageGlobals,
{IRB.CreatePointerCast(RegisteredFlag, IntptrTy)});
}
}

void ModuleAddressSanitizer::InstrumentGlobalsWithMetadataArray(
Expand All @@ -2238,10 +2262,12 @@ void ModuleAddressSanitizer::InstrumentGlobalsWithMetadataArray(

// 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<> IrbDtor(CreateAsanModuleDtor(M));
IrbDtor.CreateCall(AsanUnregisterGlobals,
{IRB.CreatePointerCast(AllGlobals, IntptrTy),
ConstantInt::get(IntptrTy, N)});
}
}

// This function replaces all global variables with new variables that have
Expand Down
22 changes: 22 additions & 0 deletions llvm/test/Instrumentation/AddressSanitizer/no_global_dtors.ll
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 7d3ef10

Please sign in to comment.