llvm.org GIT mirror llvm / 6dbe225
[NewPM][TSan] Reiterate the TSan port Summary: Second iteration of D56433 which got reverted in rL350719. The problem in the previous version was that we dropped the thunk calling the tsan init function. The new version keeps the thunk which should appease dyld, but is not actually OK wrt. the current semantics of function passes. Hence, add a helper to insert the functions only on the first time. The helper allows hooking into the insertion to be able to append them to the global ctors list. Reviewers: chandlerc, vitalybuka, fedor.sergeev, leonardchan Subscribers: hiraditya, bollu, llvm-commits Differential Revision: https://reviews.llvm.org/D56538 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@351314 91177308-0d34-0410-b5e6-96231b3b80d8 Philip Pfaffe 6 months ago
11 changed file(s) with 140 addition(s) and 43 deletion(s). Raw diff Collapse all Expand all
1616 #include "llvm/IR/Module.h"
1717 #include "llvm/Transforms/Instrumentation.h"
1818 #include "llvm/Transforms/Instrumentation/MemorySanitizer.h"
19 #include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
1920
2021 using namespace llvm;
2122
2829 }
2930
3031 void LLVMAddThreadSanitizerPass(LLVMPassManagerRef PM) {
31 unwrap(PM)->add(createThreadSanitizerPass());
32 unwrap(PM)->add(createThreadSanitizerLegacyPassPass());
3233 }
3334
3435 void LLVMAddMemorySanitizerLegacyPassPass(LLVMPassManagerRef PM) {
391391 void initializeTargetLibraryInfoWrapperPassPass(PassRegistry&);
392392 void initializeTargetPassConfigPass(PassRegistry&);
393393 void initializeTargetTransformInfoWrapperPassPass(PassRegistry&);
394 void initializeThreadSanitizerPass(PassRegistry&);
394 void initializeThreadSanitizerLegacyPassPass(PassRegistry&);
395395 void initializeTwoAddressInstructionPassPass(PassRegistry&);
396396 void initializeTypeBasedAAWrapperPassPass(PassRegistry&);
397397 void initializeUnifyFunctionExitNodesPass(PassRegistry&);
0 //===- Transforms/Instrumentation/MemorySanitizer.h - TSan Pass -----------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines the thread sanitizer pass.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #ifndef LLVM_TRANSFORMS_INSTRUMENTATION_THREADSANITIZER_H
14 #define LLVM_TRANSFORMS_INSTRUMENTATION_THREADSANITIZER_H
15
16 #include "llvm/IR/PassManager.h"
17 #include "llvm/Pass.h"
18
19 namespace llvm {
20 // Insert ThreadSanitizer (race detection) instrumentation
21 FunctionPass *createThreadSanitizerLegacyPassPass();
22
23 /// A function pass for tsan instrumentation.
24 ///
25 /// Instruments functions to detect race conditions reads. This function pass
26 /// inserts calls to runtime library functions. If the functions aren't declared
27 /// yet, the pass inserts the declarations. Otherwise the existing globals are
28 struct ThreadSanitizerPass : public PassInfoMixin {
29 PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM);
30 };
31 } // namespace llvm
32 #endif /* LLVM_TRANSFORMS_INSTRUMENTATION_THREADSANITIZER_H */
153153
154154 FunctionPass *createHWAddressSanitizerPass(bool CompileKernel = false,
155155 bool Recover = false);
156
157 // Insert ThreadSanitizer (race detection) instrumentation
158 FunctionPass *createThreadSanitizerPass();
159156
160157 // Insert DataFlowSanitizer (dynamic data flow analysis) instrumentation
161158 ModulePass *createDataFlowSanitizerPass(
5757 ArrayRef InitArgTypes, ArrayRef InitArgs,
5858 StringRef VersionCheckName = StringRef());
5959
60 /// Creates sanitizer constructor function lazily. If a constructor and init
61 /// function already exist, this function returns it. Otherwise it calls \c
62 /// createSanitizerCtorAndInitFunctions. The FunctionsCreatedCallback is invoked
63 /// in that case, passing the new Ctor and Init function.
64 ///
65 /// \return Returns pair of pointers to constructor, and init functions
66 /// respectively.
67 std::pair getOrCreateSanitizerCtorAndInitFunctions(
68 Module &M, StringRef CtorName, StringRef InitName,
69 ArrayRef InitArgTypes, ArrayRef InitArgs,
70 function_ref FunctionsCreatedCallback,
71 StringRef VersionCheckName = StringRef());
72
6073 // Creates and returns a sanitizer init function without argument if it doesn't
6174 // exist, and adds it to the global constructors list. Otherwise it returns the
6275 // existing function.
9494 #include "llvm/Transforms/Instrumentation/GCOVProfiler.h"
9595 #include "llvm/Transforms/Instrumentation/InstrProfiling.h"
9696 #include "llvm/Transforms/Instrumentation/MemorySanitizer.h"
97 #include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
9798 #include "llvm/Transforms/Instrumentation/PGOInstrumentation.h"
9899 #include "llvm/Transforms/Scalar/ADCE.h"
99100 #include "llvm/Transforms/Scalar/AlignmentFromAssumptions.h"
231231 FUNCTION_PASS("view-cfg-only", CFGOnlyViewerPass())
232232 FUNCTION_PASS("transform-warning", WarnMissedTransformationsPass())
233233 FUNCTION_PASS("msan", MemorySanitizerPass())
234 FUNCTION_PASS("tsan", ThreadSanitizerPass())
234235 #undef FUNCTION_PASS
235236
236237 #ifndef FUNCTION_PASS_WITH_PARAMS
112112 initializeInstrProfilingLegacyPassPass(Registry);
113113 initializeMemorySanitizerLegacyPassPass(Registry);
114114 initializeHWAddressSanitizerPass(Registry);
115 initializeThreadSanitizerPass(Registry);
115 initializeThreadSanitizerLegacyPassPass(Registry);
116116 initializeSanitizerCoverageModulePass(Registry);
117117 initializeDataFlowSanitizerPass(Registry);
118118 initializeEfficiencySanitizerPass(Registry);
1818 // The rest is handled by the run-time library.
1919 //===----------------------------------------------------------------------===//
2020
21 #include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
2122 #include "llvm/ADT/SmallPtrSet.h"
2223 #include "llvm/ADT/SmallString.h"
2324 #include "llvm/ADT/SmallVector.h"
8586 namespace {
8687
8788 /// ThreadSanitizer: instrument the code in module to find races.
88 struct ThreadSanitizer : public FunctionPass {
89 ThreadSanitizer() : FunctionPass(ID) {}
90 StringRef getPassName() const override;
91 void getAnalysisUsage(AnalysisUsage &AU) const override;
92 bool runOnFunction(Function &F) override;
93 bool doInitialization(Module &M) override;
94 static char ID; // Pass identification, replacement for typeid.
95
96 private:
89 ///
90 /// Instantiating ThreadSanitizer inserts the tsan runtime library API function
91 /// declarations into the module if they don't exist already. Instantiating
92 /// ensures the __tsan_init function is in the list of global constructors for
93 /// the module.
94 struct ThreadSanitizer {
95 ThreadSanitizer(Module &M);
96 bool sanitizeFunction(Function &F, const TargetLibraryInfo &TLI);
97
98 private:
9799 void initializeCallbacks(Module &M);
98100 bool instrumentLoadOrStore(Instruction *I, const DataLayout &DL);
99101 bool instrumentAtomic(Instruction *I, const DataLayout &DL);
129131 Function *MemmoveFn, *MemcpyFn, *MemsetFn;
130132 Function *TsanCtorFunction;
131133 };
134
135 struct ThreadSanitizerLegacyPass : FunctionPass {
136 ThreadSanitizerLegacyPass() : FunctionPass(ID) {}
137 StringRef getPassName() const override;
138 void getAnalysisUsage(AnalysisUsage &AU) const override;
139 bool runOnFunction(Function &F) override;
140 bool doInitialization(Module &M) override;
141 static char ID; // Pass identification, replacement for typeid.
142 private:
143 Optional TSan;
144 };
132145 } // namespace
133146
134 char ThreadSanitizer::ID = 0;
135 INITIALIZE_PASS_BEGIN(
136 ThreadSanitizer, "tsan",
137 "ThreadSanitizer: detects data races.",
138 false, false)
147 PreservedAnalyses ThreadSanitizerPass::run(Function &F,
148 FunctionAnalysisManager &FAM) {
149 ThreadSanitizer TSan(*F.getParent());
150 if (TSan.sanitizeFunction(F, FAM.getResult(F)))
151 return PreservedAnalyses::none();
152 return PreservedAnalyses::all();
153 }
154
155 char ThreadSanitizerLegacyPass::ID = 0;
156 INITIALIZE_PASS_BEGIN(ThreadSanitizerLegacyPass, "tsan",
157 "ThreadSanitizer: detects data races.", false, false)
139158 INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
140 INITIALIZE_PASS_END(
141 ThreadSanitizer, "tsan",
142 "ThreadSanitizer: detects data races.",
143 false, false)
144
145 StringRef ThreadSanitizer::getPassName() const { return "ThreadSanitizer"; }
146
147 void ThreadSanitizer::getAnalysisUsage(AnalysisUsage &AU) const {
159 INITIALIZE_PASS_END(ThreadSanitizerLegacyPass, "tsan",
160 "ThreadSanitizer: detects data races.", false, false)
161
162 StringRef ThreadSanitizerLegacyPass::getPassName() const {
163 return "ThreadSanitizerLegacyPass";
164 }
165
166 void ThreadSanitizerLegacyPass::getAnalysisUsage(AnalysisUsage &AU) const {
148167 AU.addRequired();
149168 }
150169
151 FunctionPass *llvm::createThreadSanitizerPass() {
152 return new ThreadSanitizer();
170 bool ThreadSanitizerLegacyPass::doInitialization(Module &M) {
171 TSan.emplace(M);
172 return true;
173 }
174
175 bool ThreadSanitizerLegacyPass::runOnFunction(Function &F) {
176 auto &TLI = getAnalysis().getTLI();
177 TSan->sanitizeFunction(F, TLI);
178 return true;
179 }
180
181 FunctionPass *llvm::createThreadSanitizerLegacyPassPass() {
182 return new ThreadSanitizerLegacyPass();
153183 }
154184
155185 void ThreadSanitizer::initializeCallbacks(Module &M) {
251281 IRB.getInt32Ty(), IntptrTy));
252282 }
253283
254 bool ThreadSanitizer::doInitialization(Module &M) {
284 ThreadSanitizer::ThreadSanitizer(Module &M) {
255285 const DataLayout &DL = M.getDataLayout();
256286 IntptrTy = DL.getIntPtrType(M.getContext());
257 std::tie(TsanCtorFunction, std::ignore) = createSanitizerCtorAndInitFunctions(
258 M, kTsanModuleCtorName, kTsanInitName, /*InitArgTypes=*/{},
259 /*InitArgs=*/{});
260
261 appendToGlobalCtors(M, TsanCtorFunction, 0);
262
263 return true;
287 std::tie(TsanCtorFunction, std::ignore) =
288 getOrCreateSanitizerCtorAndInitFunctions(
289 M, kTsanModuleCtorName, kTsanInitName, /*InitArgTypes=*/{},
290 /*InitArgs=*/{},
291 // This callback is invoked when the functions are created the first
292 // time. Hook them into the global ctors list in that case:
293 [&](Function *Ctor, Function *) { appendToGlobalCtors(M, Ctor, 0); });
264294 }
265295
266296 static bool isVtableAccess(Instruction *I) {
401431 }
402432 }
403433
404 bool ThreadSanitizer::runOnFunction(Function &F) {
434 bool ThreadSanitizer::sanitizeFunction(Function &F,
435 const TargetLibraryInfo &TLI) {
405436 // This is required to prevent instrumenting call to __tsan_init from within
406437 // the module constructor.
407438 if (&F == TsanCtorFunction)
415446 bool HasCalls = false;
416447 bool SanitizeFunction = F.hasFnAttribute(Attribute::SanitizeThread);
417448 const DataLayout &DL = F.getParent()->getDataLayout();
418 const TargetLibraryInfo *TLI =
419 &getAnalysis().getTLI();
420449
421450 // Traverse all instructions, collect loads/stores/returns, check for calls.
422451 for (auto &BB : F) {
427456 LocalLoadsAndStores.push_back(&Inst);
428457 else if (isa(Inst) || isa(Inst)) {
429458 if (CallInst *CI = dyn_cast(&Inst))
430 maybeMarkSanitizerLibraryCallNoBuiltin(CI, TLI);
459 maybeMarkSanitizerLibraryCallNoBuiltin(CI, &TLI);
431460 if (isa(Inst))
432461 MemIntrinCalls.push_back(&Inst);
433462 HasCalls = true;
173173 return std::make_pair(Ctor, InitFunction);
174174 }
175175
176 std::pair
177 llvm::getOrCreateSanitizerCtorAndInitFunctions(
178 Module &M, StringRef CtorName, StringRef InitName,
179 ArrayRef InitArgTypes, ArrayRef InitArgs,
180 function_ref FunctionsCreatedCallback,
181 StringRef VersionCheckName) {
182 assert(!CtorName.empty() && "Expected ctor function name");
183
184 if (Function *Ctor = M.getFunction(CtorName))
185 // FIXME: Sink this logic into the module, similar to the handling of
186 // globals. This will make moving to a concurrent model much easier.
187 if (Ctor->arg_size() == 0 ||
188 Ctor->getReturnType() == Type::getVoidTy(M.getContext()))
189 return {Ctor, declareSanitizerInitFunction(M, InitName, InitArgTypes)};
190
191 Function *Ctor, *InitFunction;
192 std::tie(Ctor, InitFunction) = llvm::createSanitizerCtorAndInitFunctions(
193 M, CtorName, InitName, InitArgTypes, InitArgs, VersionCheckName);
194 FunctionsCreatedCallback(Ctor, InitFunction);
195 return std::make_pair(Ctor, InitFunction);
196 }
197
176198 Function *llvm::getOrCreateInitFunction(Module &M, StringRef Name) {
177199 assert(!Name.empty() && "Expected init function name");
178200 if (Function *F = M.getFunction(Name)) {
0 ; RUN: opt < %s -tsan -S | FileCheck %s
1 ; RUN: opt < %s -passes=tsan -S | FileCheck %s
12
23 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"
34 target triple = "x86_64-unknown-linux-gnu"
7677 call void @SwiftError(i8** %0)
7778 ret void
7879 }
79
8080 ; CHECK: define internal void @tsan.module_ctor()
8181 ; CHECK: call void @__tsan_init()