Skip to content

Commit 436fb2b

Browse files
committedFeb 13, 2019
[NewPM] Second attempt at porting ASan
This is the second attempt to port ASan to new PM after D52739. This takes the initialization requried by ASan from the Module by moving it into a separate class with it's own analysis that the new PM ASan can use. Changes: - Split AddressSanitizer into 2 passes: 1 for the instrumentation on the function, and 1 for the pass itself which creates an instance of the first during it's run. The same is done for AddressSanitizerModule. - Add new PM AddressSanitizer and AddressSanitizerModule. - Add legacy and new PM analyses for reading data needed to initialize ASan with. - Removed DominatorTree dependency from ASan since it was unused. - Move GlobalsMetadata and ShadowMapping out of anonymous namespace since the new PM analysis holds these 2 classes and will need to expose them. Differential Revision: https://reviews.llvm.org/D56470 llvm-svn: 353985
1 parent 04306d6 commit 436fb2b

File tree

11 files changed

+489
-200
lines changed

11 files changed

+489
-200
lines changed
 

‎clang/lib/CodeGen/BackendUtil.cpp

+43-3
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
#include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h"
5454
#include "llvm/Transforms/InstCombine/InstCombine.h"
5555
#include "llvm/Transforms/Instrumentation.h"
56+
#include "llvm/Transforms/Instrumentation/AddressSanitizer.h"
5657
#include "llvm/Transforms/Instrumentation/BoundsChecking.h"
5758
#include "llvm/Transforms/Instrumentation/GCOVProfiler.h"
5859
#include "llvm/Transforms/Instrumentation/MemorySanitizer.h"
@@ -243,15 +244,15 @@ static void addAddressSanitizerPasses(const PassManagerBuilder &Builder,
243244
bool UseGlobalsGC = asanUseGlobalsGC(T, CGOpts);
244245
PM.add(createAddressSanitizerFunctionPass(/*CompileKernel*/ false, Recover,
245246
UseAfterScope));
246-
PM.add(createAddressSanitizerModulePass(/*CompileKernel*/ false, Recover,
247-
UseGlobalsGC, UseOdrIndicator));
247+
PM.add(createModuleAddressSanitizerLegacyPassPass(
248+
/*CompileKernel*/ false, Recover, UseGlobalsGC, UseOdrIndicator));
248249
}
249250

250251
static void addKernelAddressSanitizerPasses(const PassManagerBuilder &Builder,
251252
legacy::PassManagerBase &PM) {
252253
PM.add(createAddressSanitizerFunctionPass(
253254
/*CompileKernel*/ true, /*Recover*/ true, /*UseAfterScope*/ false));
254-
PM.add(createAddressSanitizerModulePass(
255+
PM.add(createModuleAddressSanitizerLegacyPassPass(
255256
/*CompileKernel*/ true, /*Recover*/ true, /*UseGlobalsGC*/ true,
256257
/*UseOdrIndicator*/ false));
257258
}
@@ -917,6 +918,22 @@ static PassBuilder::OptimizationLevel mapToLevel(const CodeGenOptions &Opts) {
917918
}
918919
}
919920

921+
void addSanitizersAtO0(ModulePassManager &MPM, const Triple &TargetTriple,
922+
const LangOptions &LangOpts,
923+
const CodeGenOptions &CodeGenOpts) {
924+
if (LangOpts.Sanitize.has(SanitizerKind::Address)) {
925+
MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>());
926+
bool Recover = CodeGenOpts.SanitizeRecover.has(SanitizerKind::Address);
927+
MPM.addPass(createModuleToFunctionPassAdaptor(
928+
AddressSanitizerPass(/*CompileKernel=*/false, Recover,
929+
CodeGenOpts.SanitizeAddressUseAfterScope)));
930+
bool ModuleUseAfterScope = asanUseGlobalsGC(TargetTriple, CodeGenOpts);
931+
MPM.addPass(ModuleAddressSanitizerPass(
932+
/*CompileKernel=*/false, Recover, ModuleUseAfterScope,
933+
CodeGenOpts.SanitizeAddressUseOdrIndicator));
934+
}
935+
}
936+
920937
/// A clean version of `EmitAssembly` that uses the new pass manager.
921938
///
922939
/// Not all features are currently supported in this system, but where
@@ -1043,6 +1060,26 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
10431060
[](FunctionPassManager &FPM, PassBuilder::OptimizationLevel Level) {
10441061
FPM.addPass(ThreadSanitizerPass());
10451062
});
1063+
if (LangOpts.Sanitize.has(SanitizerKind::Address)) {
1064+
PB.registerPipelineStartEPCallback([&](ModulePassManager &MPM) {
1065+
MPM.addPass(
1066+
RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>());
1067+
});
1068+
bool Recover = CodeGenOpts.SanitizeRecover.has(SanitizerKind::Address);
1069+
PB.registerOptimizerLastEPCallback(
1070+
[&](FunctionPassManager &FPM,
1071+
PassBuilder::OptimizationLevel Level) {
1072+
FPM.addPass(AddressSanitizerPass(
1073+
/*CompileKernel=*/false, Recover,
1074+
CodeGenOpts.SanitizeAddressUseAfterScope));
1075+
});
1076+
bool ModuleUseAfterScope = asanUseGlobalsGC(TargetTriple, CodeGenOpts);
1077+
PB.registerPipelineStartEPCallback([&](ModulePassManager &MPM) {
1078+
MPM.addPass(ModuleAddressSanitizerPass(
1079+
/*CompileKernel=*/false, Recover, ModuleUseAfterScope,
1080+
CodeGenOpts.SanitizeAddressUseOdrIndicator));
1081+
});
1082+
}
10461083
if (Optional<GCOVOptions> Options = getGCOVOptions(CodeGenOpts))
10471084
PB.registerPipelineStartEPCallback([Options](ModulePassManager &MPM) {
10481085
MPM.addPass(GCOVProfilerPass(*Options));
@@ -1063,6 +1100,9 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
10631100
CodeGenOpts.DebugPassManager);
10641101
}
10651102
}
1103+
1104+
if (CodeGenOpts.OptimizationLevel == 0)
1105+
addSanitizersAtO0(MPM, TargetTriple, LangOpts, CodeGenOpts);
10661106
}
10671107

10681108
// FIXME: We still use the legacy pass manager to do code generation. We

‎clang/test/CodeGen/asan-new-pm.ll

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
; Test that ASan runs with the new pass manager
2+
; RUN: %clang_cc1 -S -emit-llvm -o - -fexperimental-new-pass-manager -fsanitize=address %s | FileCheck %s --check-prefixes=CHECK,LTO,THINLTO
3+
; RUN: %clang_cc1 -S -emit-llvm -o - -fexperimental-new-pass-manager -fsanitize=address -flto %s | FileCheck %s --check-prefixes=CHECK,LTO
4+
; RUN: %clang_cc1 -S -emit-llvm -o - -fexperimental-new-pass-manager -fsanitize=address -flto=thin %s | FileCheck %s --check-prefixes=CHECK,THINLTO
5+
; RUN: %clang_cc1 -S -emit-llvm -o - -O1 -fexperimental-new-pass-manager -fsanitize=address %s | FileCheck %s --check-prefixes=CHECK,LTO,THINLTO
6+
; RUN: %clang_cc1 -S -emit-llvm -o - -O1 -fexperimental-new-pass-manager -fsanitize=address -flto %s | FileCheck %s --check-prefixes=CHECK,LTO
7+
; RUN: %clang_cc1 -S -emit-llvm -o - -O1 -fexperimental-new-pass-manager -fsanitize=address -flto=thin %s | FileCheck %s --check-prefixes=CHECK,THINLTO
8+
9+
; DAG-CHECK: @llvm.global_ctors = {{.*}}@asan.module_ctor
10+
11+
define i32 @test_load(i32* %a) sanitize_address {
12+
entry:
13+
%tmp1 = load i32, i32* %a, align 4
14+
ret i32 %tmp1
15+
}
16+
17+
; CHECK: __asan_init
18+
19+
; DAG-CHECK: define internal void @asan.module_ctor() {
20+
; CHECK: {{.*}} call void @__asan_init()
21+
; CHECK: {{.*}} call void @__asan_version_mismatch_check_v8()
22+
; CHECK: ret void
23+
; CHECK: }
24+
25+
; DAG-CHECK: __asan_version_mismatch_check_v8
26+
27+
; This is not used in ThinLTO
28+
; DAG-LTO: __asan_report_load4

‎llvm/bindings/go/llvm/InstrumentationBindings.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "llvm/IR/LegacyPassManager.h"
1616
#include "llvm/IR/Module.h"
1717
#include "llvm/Transforms/Instrumentation.h"
18+
#include "llvm/Transforms/Instrumentation/AddressSanitizer.h"
1819
#include "llvm/Transforms/Instrumentation/MemorySanitizer.h"
1920
#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
2021

@@ -25,7 +26,7 @@ void LLVMAddAddressSanitizerFunctionPass(LLVMPassManagerRef PM) {
2526
}
2627

2728
void LLVMAddAddressSanitizerModulePass(LLVMPassManagerRef PM) {
28-
unwrap(PM)->add(createAddressSanitizerModulePass());
29+
unwrap(PM)->add(createModuleAddressSanitizerLegacyPassPass());
2930
}
3031

3132
void LLVMAddThreadSanitizerPass(LLVMPassManagerRef PM) {

‎llvm/include/llvm/InitializePasses.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,9 @@ void initializeAAEvalLegacyPassPass(PassRegistry&);
6464
void initializeAAResultsWrapperPassPass(PassRegistry&);
6565
void initializeADCELegacyPassPass(PassRegistry&);
6666
void initializeAddDiscriminatorsLegacyPassPass(PassRegistry&);
67-
void initializeAddressSanitizerModulePass(PassRegistry&);
68-
void initializeAddressSanitizerPass(PassRegistry&);
67+
void initializeModuleAddressSanitizerLegacyPassPass(PassRegistry &);
68+
void initializeASanGlobalsMetadataWrapperPassPass(PassRegistry &);
69+
void initializeAddressSanitizerLegacyPassPass(PassRegistry &);
6970
void initializeAggressiveInstCombinerLegacyPassPass(PassRegistry&);
7071
void initializeAliasSetPrinterPass(PassRegistry&);
7172
void initializeAlignmentFromAssumptionsPass(PassRegistry&);

‎llvm/include/llvm/Transforms/Instrumentation.h

-9
Original file line numberDiff line numberDiff line change
@@ -142,15 +142,6 @@ struct InstrProfOptions {
142142
ModulePass *createInstrProfilingLegacyPass(
143143
const InstrProfOptions &Options = InstrProfOptions());
144144

145-
// Insert AddressSanitizer (address sanity checking) instrumentation
146-
FunctionPass *createAddressSanitizerFunctionPass(bool CompileKernel = false,
147-
bool Recover = false,
148-
bool UseAfterScope = false);
149-
ModulePass *createAddressSanitizerModulePass(bool CompileKernel = false,
150-
bool Recover = false,
151-
bool UseGlobalsGC = true,
152-
bool UseOdrIndicator = true);
153-
154145
FunctionPass *createHWAddressSanitizerPass(bool CompileKernel = false,
155146
bool Recover = false);
156147

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
//===--------- Definition of the AddressSanitizer class ---------*- C++ -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// This file declares the AddressSanitizer class which is a port of the legacy
11+
// AddressSanitizer pass to use the new PassManager infrastructure.
12+
//
13+
//===----------------------------------------------------------------------===//
14+
#ifndef LLVM_TRANSFORMS_INSTRUMENTATION_ADDRESSSANITIZERPASS_H
15+
#define LLVM_TRANSFORMS_INSTRUMENTATION_ADDRESSSANITIZERPASS_H
16+
17+
#include "llvm/IR/Function.h"
18+
#include "llvm/IR/Module.h"
19+
#include "llvm/IR/PassManager.h"
20+
21+
namespace llvm {
22+
23+
/// Frontend-provided metadata for source location.
24+
struct LocationMetadata {
25+
StringRef Filename;
26+
int LineNo = 0;
27+
int ColumnNo = 0;
28+
29+
LocationMetadata() = default;
30+
31+
bool empty() const { return Filename.empty(); }
32+
void parse(MDNode *MDN);
33+
};
34+
35+
/// Frontend-provided metadata for global variables.
36+
class GlobalsMetadata {
37+
public:
38+
struct Entry {
39+
LocationMetadata SourceLoc;
40+
StringRef Name;
41+
bool IsDynInit = false;
42+
bool IsBlacklisted = false;
43+
44+
Entry() = default;
45+
};
46+
47+
/// Create a default uninitialized GlobalsMetadata instance.
48+
GlobalsMetadata() = default;
49+
50+
/// Create an initialized GlobalsMetadata instance.
51+
GlobalsMetadata(Module &M);
52+
53+
/// Returns metadata entry for a given global.
54+
Entry get(GlobalVariable *G) const {
55+
auto Pos = Entries.find(G);
56+
return (Pos != Entries.end()) ? Pos->second : Entry();
57+
}
58+
59+
/// Handle invalidation from the pass manager.
60+
/// These results are never invalidated.
61+
bool invalidate(Module &, const PreservedAnalyses &,
62+
ModuleAnalysisManager::Invalidator &) {
63+
return false;
64+
}
65+
bool invalidate(Function &, const PreservedAnalyses &,
66+
FunctionAnalysisManager::Invalidator &) {
67+
return false;
68+
}
69+
70+
private:
71+
DenseMap<GlobalVariable *, Entry> Entries;
72+
};
73+
74+
/// The ASanGlobalsMetadataAnalysis initializes and returns a GlobalsMetadata
75+
/// object. More specifically, ASan requires looking at all globals registered
76+
/// in 'llvm.asan.globals' before running, which only depends on reading module
77+
/// level metadata. This analysis is required to run before running the
78+
/// AddressSanitizerPass since it collects that metadata.
79+
/// The legacy pass manager equivalent of this is ASanGlobalsMetadataLegacyPass.
80+
class ASanGlobalsMetadataAnalysis
81+
: public AnalysisInfoMixin<ASanGlobalsMetadataAnalysis> {
82+
public:
83+
using Result = GlobalsMetadata;
84+
85+
Result run(Module &, ModuleAnalysisManager &);
86+
87+
private:
88+
friend AnalysisInfoMixin<ASanGlobalsMetadataAnalysis>;
89+
static AnalysisKey Key;
90+
};
91+
92+
/// Public interface to the address sanitizer pass for instrumenting code to
93+
/// check for various memory errors at runtime.
94+
///
95+
/// The sanitizer itself is a function pass that works by inserting various
96+
/// calls to the ASan runtime library functions. The runtime library essentially
97+
/// replaces malloc() and free() with custom implementations that allow regions
98+
/// surrounding requested memory to be checked for invalid accesses.
99+
class AddressSanitizerPass : public PassInfoMixin<AddressSanitizerPass> {
100+
public:
101+
explicit AddressSanitizerPass(bool CompileKernel = false,
102+
bool Recover = false,
103+
bool UseAfterScope = false);
104+
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
105+
106+
private:
107+
bool CompileKernel;
108+
bool Recover;
109+
bool UseAfterScope;
110+
};
111+
112+
/// Public interface to the address sanitizer module pass for instrumenting code
113+
/// to check for various memory errors.
114+
///
115+
/// This adds 'asan.module_ctor' to 'llvm.global_ctors'. This pass may also
116+
/// run intependently of the function address sanitizer.
117+
class ModuleAddressSanitizerPass
118+
: public PassInfoMixin<ModuleAddressSanitizerPass> {
119+
public:
120+
explicit ModuleAddressSanitizerPass(bool CompileKernel = false,
121+
bool Recover = false,
122+
bool UseGlobalGC = true,
123+
bool UseOdrIndicator = false);
124+
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
125+
126+
private:
127+
bool CompileKernel;
128+
bool Recover;
129+
bool UseGlobalGC;
130+
bool UseOdrIndicator;
131+
};
132+
133+
// Insert AddressSanitizer (address sanity checking) instrumentation
134+
FunctionPass *createAddressSanitizerFunctionPass(bool CompileKernel = false,
135+
bool Recover = false,
136+
bool UseAfterScope = false);
137+
ModulePass *createModuleAddressSanitizerLegacyPassPass(
138+
bool CompileKernel = false, bool Recover = false, bool UseGlobalsGC = true,
139+
bool UseOdrIndicator = true);
140+
141+
} // namespace llvm
142+
143+
#endif

‎llvm/lib/Passes/PassBuilder.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -88,14 +88,15 @@
8888
#include "llvm/Transforms/IPO/WholeProgramDevirt.h"
8989
#include "llvm/Transforms/InstCombine/InstCombine.h"
9090
#include "llvm/Transforms/Instrumentation.h"
91+
#include "llvm/Transforms/Instrumentation/AddressSanitizer.h"
9192
#include "llvm/Transforms/Instrumentation/BoundsChecking.h"
9293
#include "llvm/Transforms/Instrumentation/CGProfile.h"
9394
#include "llvm/Transforms/Instrumentation/ControlHeightReduction.h"
9495
#include "llvm/Transforms/Instrumentation/GCOVProfiler.h"
9596
#include "llvm/Transforms/Instrumentation/InstrProfiling.h"
9697
#include "llvm/Transforms/Instrumentation/MemorySanitizer.h"
97-
#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
9898
#include "llvm/Transforms/Instrumentation/PGOInstrumentation.h"
99+
#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
99100
#include "llvm/Transforms/Scalar/ADCE.h"
100101
#include "llvm/Transforms/Scalar/AlignmentFromAssumptions.h"
101102
#include "llvm/Transforms/Scalar/BDCE.h"

‎llvm/lib/Passes/PassRegistry.def

+3
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ MODULE_ANALYSIS("stack-safety", StackSafetyGlobalAnalysis())
2727
MODULE_ANALYSIS("targetlibinfo", TargetLibraryAnalysis())
2828
MODULE_ANALYSIS("verify", VerifierAnalysis())
2929
MODULE_ANALYSIS("pass-instrumentation", PassInstrumentationAnalysis(PIC))
30+
MODULE_ANALYSIS("asan-globals-md", ASanGlobalsMetadataAnalysis())
3031

3132
#ifndef MODULE_ALIAS_ANALYSIS
3233
#define MODULE_ALIAS_ANALYSIS(NAME, CREATE_PASS) \
@@ -81,6 +82,7 @@ MODULE_PASS("strip-dead-prototypes", StripDeadPrototypesPass())
8182
MODULE_PASS("synthetic-counts-propagation", SyntheticCountsPropagation())
8283
MODULE_PASS("wholeprogramdevirt", WholeProgramDevirtPass(nullptr, nullptr))
8384
MODULE_PASS("verify", VerifierPass())
85+
MODULE_PASS("asan-module", ModuleAddressSanitizerPass(false, false, true, false))
8486
#undef MODULE_PASS
8587

8688
#ifndef CGSCC_ANALYSIS
@@ -231,6 +233,7 @@ FUNCTION_PASS("verify<regions>", RegionInfoVerifierPass())
231233
FUNCTION_PASS("view-cfg", CFGViewerPass())
232234
FUNCTION_PASS("view-cfg-only", CFGOnlyViewerPass())
233235
FUNCTION_PASS("transform-warning", WarnMissedTransformationsPass())
236+
FUNCTION_PASS("asan", AddressSanitizerPass(false, false, false))
234237
FUNCTION_PASS("msan", MemorySanitizerPass({}))
235238
FUNCTION_PASS("tsan", ThreadSanitizerPass())
236239
#undef FUNCTION_PASS

0 commit comments

Comments
 (0)