mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-04-01 07:11:45 +00:00
[tsan,msan] Insert module constructors in a module pass
Summary: If we insert them from function pass some analysis may be missing or invalid. Fixes PR42877. Reviewers: eugenis, leonardchan Reviewed By: leonardchan Subscribers: hiraditya, cfe-commits, llvm-commits Tags: #clang, #llvm Differential Revision: https://reviews.llvm.org/D68832 llvm-svn: 374481
This commit is contained in:
parent
b6e2d1b8ae
commit
ff18cfe664
@ -40,6 +40,7 @@ struct MemorySanitizerPass : public PassInfoMixin<MemorySanitizerPass> {
|
||||
MemorySanitizerPass(MemorySanitizerOptions Options) : Options(Options) {}
|
||||
|
||||
PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM);
|
||||
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
|
||||
|
||||
private:
|
||||
MemorySanitizerOptions Options;
|
||||
|
@ -27,6 +27,8 @@ FunctionPass *createThreadSanitizerLegacyPassPass();
|
||||
/// yet, the pass inserts the declarations. Otherwise the existing globals are
|
||||
struct ThreadSanitizerPass : public PassInfoMixin<ThreadSanitizerPass> {
|
||||
PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM);
|
||||
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
#endif /* LLVM_TRANSFORMS_INSTRUMENTATION_THREADSANITIZER_H */
|
||||
|
@ -86,6 +86,8 @@ MODULE_PASS("synthetic-counts-propagation", SyntheticCountsPropagation())
|
||||
MODULE_PASS("wholeprogramdevirt", WholeProgramDevirtPass(nullptr, nullptr))
|
||||
MODULE_PASS("verify", VerifierPass())
|
||||
MODULE_PASS("asan-module", ModuleAddressSanitizerPass(/*CompileKernel=*/false, false, true, false))
|
||||
MODULE_PASS("msan-module", MemorySanitizerPass({}))
|
||||
MODULE_PASS("tsan-module", ThreadSanitizerPass())
|
||||
MODULE_PASS("kasan-module", ModuleAddressSanitizerPass(/*CompileKernel=*/true, false, true, false))
|
||||
MODULE_PASS("sancov-module", ModuleSanitizerCoveragePass())
|
||||
MODULE_PASS("poison-checking", PoisonCheckingPass())
|
||||
|
@ -587,10 +587,26 @@ private:
|
||||
|
||||
/// An empty volatile inline asm that prevents callback merge.
|
||||
InlineAsm *EmptyAsm;
|
||||
|
||||
Function *MsanCtorFunction;
|
||||
};
|
||||
|
||||
void insertModuleCtor(Module &M) {
|
||||
getOrCreateSanitizerCtorAndInitFunctions(
|
||||
M, kMsanModuleCtorName, kMsanInitName,
|
||||
/*InitArgTypes=*/{},
|
||||
/*InitArgs=*/{},
|
||||
// This callback is invoked when the functions are created the first
|
||||
// time. Hook them into the global ctors list in that case:
|
||||
[&](Function *Ctor, FunctionCallee) {
|
||||
if (!ClWithComdat) {
|
||||
appendToGlobalCtors(M, Ctor, 0);
|
||||
return;
|
||||
}
|
||||
Comdat *MsanCtorComdat = M.getOrInsertComdat(kMsanModuleCtorName);
|
||||
Ctor->setComdat(MsanCtorComdat);
|
||||
appendToGlobalCtors(M, Ctor, 0, Ctor);
|
||||
});
|
||||
}
|
||||
|
||||
/// A legacy function pass for msan instrumentation.
|
||||
///
|
||||
/// Instruments functions to detect unitialized reads.
|
||||
@ -635,6 +651,14 @@ PreservedAnalyses MemorySanitizerPass::run(Function &F,
|
||||
return PreservedAnalyses::all();
|
||||
}
|
||||
|
||||
PreservedAnalyses MemorySanitizerPass::run(Module &M,
|
||||
ModuleAnalysisManager &AM) {
|
||||
if (Options.Kernel)
|
||||
return PreservedAnalyses::all();
|
||||
insertModuleCtor(M);
|
||||
return PreservedAnalyses::none();
|
||||
}
|
||||
|
||||
char MemorySanitizerLegacyPass::ID = 0;
|
||||
|
||||
INITIALIZE_PASS_BEGIN(MemorySanitizerLegacyPass, "msan",
|
||||
@ -920,23 +944,6 @@ void MemorySanitizer::initializeModule(Module &M) {
|
||||
OriginStoreWeights = MDBuilder(*C).createBranchWeights(1, 1000);
|
||||
|
||||
if (!CompileKernel) {
|
||||
std::tie(MsanCtorFunction, std::ignore) =
|
||||
getOrCreateSanitizerCtorAndInitFunctions(
|
||||
M, kMsanModuleCtorName, kMsanInitName,
|
||||
/*InitArgTypes=*/{},
|
||||
/*InitArgs=*/{},
|
||||
// This callback is invoked when the functions are created the first
|
||||
// time. Hook them into the global ctors list in that case:
|
||||
[&](Function *Ctor, FunctionCallee) {
|
||||
if (!ClWithComdat) {
|
||||
appendToGlobalCtors(M, Ctor, 0);
|
||||
return;
|
||||
}
|
||||
Comdat *MsanCtorComdat = M.getOrInsertComdat(kMsanModuleCtorName);
|
||||
Ctor->setComdat(MsanCtorComdat);
|
||||
appendToGlobalCtors(M, Ctor, 0, Ctor);
|
||||
});
|
||||
|
||||
if (TrackOrigins)
|
||||
M.getOrInsertGlobal("__msan_track_origins", IRB.getInt32Ty(), [&] {
|
||||
return new GlobalVariable(
|
||||
@ -954,6 +961,8 @@ void MemorySanitizer::initializeModule(Module &M) {
|
||||
}
|
||||
|
||||
bool MemorySanitizerLegacyPass::doInitialization(Module &M) {
|
||||
if (!Options.Kernel)
|
||||
insertModuleCtor(M);
|
||||
MSan.emplace(M, Options);
|
||||
return true;
|
||||
}
|
||||
@ -4578,8 +4587,9 @@ static VarArgHelper *CreateVarArgHelper(Function &Func, MemorySanitizer &Msan,
|
||||
}
|
||||
|
||||
bool MemorySanitizer::sanitizeFunction(Function &F, TargetLibraryInfo &TLI) {
|
||||
if (!CompileKernel && (&F == MsanCtorFunction))
|
||||
if (!CompileKernel && F.getName() == kMsanModuleCtorName)
|
||||
return false;
|
||||
|
||||
MemorySanitizerVisitor Visitor(F, *this, TLI);
|
||||
|
||||
// Clear out readonly/readnone attributes.
|
||||
|
@ -92,11 +92,10 @@ namespace {
|
||||
/// ensures the __tsan_init function is in the list of global constructors for
|
||||
/// the module.
|
||||
struct ThreadSanitizer {
|
||||
ThreadSanitizer(Module &M);
|
||||
bool sanitizeFunction(Function &F, const TargetLibraryInfo &TLI);
|
||||
|
||||
private:
|
||||
void initializeCallbacks(Module &M);
|
||||
void initialize(Module &M);
|
||||
bool instrumentLoadOrStore(Instruction *I, const DataLayout &DL);
|
||||
bool instrumentAtomic(Instruction *I, const DataLayout &DL);
|
||||
bool instrumentMemIntrinsic(Instruction *I);
|
||||
@ -108,8 +107,6 @@ private:
|
||||
void InsertRuntimeIgnores(Function &F);
|
||||
|
||||
Type *IntptrTy;
|
||||
IntegerType *OrdTy;
|
||||
// Callbacks to run-time library are computed in doInitialization.
|
||||
FunctionCallee TsanFuncEntry;
|
||||
FunctionCallee TsanFuncExit;
|
||||
FunctionCallee TsanIgnoreBegin;
|
||||
@ -130,7 +127,6 @@ private:
|
||||
FunctionCallee TsanVptrUpdate;
|
||||
FunctionCallee TsanVptrLoad;
|
||||
FunctionCallee MemmoveFn, MemcpyFn, MemsetFn;
|
||||
Function *TsanCtorFunction;
|
||||
};
|
||||
|
||||
struct ThreadSanitizerLegacyPass : FunctionPass {
|
||||
@ -143,16 +139,32 @@ struct ThreadSanitizerLegacyPass : FunctionPass {
|
||||
private:
|
||||
Optional<ThreadSanitizer> TSan;
|
||||
};
|
||||
|
||||
void insertModuleCtor(Module &M) {
|
||||
getOrCreateSanitizerCtorAndInitFunctions(
|
||||
M, kTsanModuleCtorName, kTsanInitName, /*InitArgTypes=*/{},
|
||||
/*InitArgs=*/{},
|
||||
// This callback is invoked when the functions are created the first
|
||||
// time. Hook them into the global ctors list in that case:
|
||||
[&](Function *Ctor, FunctionCallee) { appendToGlobalCtors(M, Ctor, 0); });
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
PreservedAnalyses ThreadSanitizerPass::run(Function &F,
|
||||
FunctionAnalysisManager &FAM) {
|
||||
ThreadSanitizer TSan(*F.getParent());
|
||||
ThreadSanitizer TSan;
|
||||
if (TSan.sanitizeFunction(F, FAM.getResult<TargetLibraryAnalysis>(F)))
|
||||
return PreservedAnalyses::none();
|
||||
return PreservedAnalyses::all();
|
||||
}
|
||||
|
||||
PreservedAnalyses ThreadSanitizerPass::run(Module &M,
|
||||
ModuleAnalysisManager &MAM) {
|
||||
insertModuleCtor(M);
|
||||
return PreservedAnalyses::none();
|
||||
}
|
||||
|
||||
char ThreadSanitizerLegacyPass::ID = 0;
|
||||
INITIALIZE_PASS_BEGIN(ThreadSanitizerLegacyPass, "tsan",
|
||||
"ThreadSanitizer: detects data races.", false, false)
|
||||
@ -169,7 +181,8 @@ void ThreadSanitizerLegacyPass::getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
}
|
||||
|
||||
bool ThreadSanitizerLegacyPass::doInitialization(Module &M) {
|
||||
TSan.emplace(M);
|
||||
insertModuleCtor(M);
|
||||
TSan.emplace();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -183,7 +196,10 @@ FunctionPass *llvm::createThreadSanitizerLegacyPassPass() {
|
||||
return new ThreadSanitizerLegacyPass();
|
||||
}
|
||||
|
||||
void ThreadSanitizer::initializeCallbacks(Module &M) {
|
||||
void ThreadSanitizer::initialize(Module &M) {
|
||||
const DataLayout &DL = M.getDataLayout();
|
||||
IntptrTy = DL.getIntPtrType(M.getContext());
|
||||
|
||||
IRBuilder<> IRB(M.getContext());
|
||||
AttributeList Attr;
|
||||
Attr = Attr.addAttribute(M.getContext(), AttributeList::FunctionIndex,
|
||||
@ -197,7 +213,7 @@ void ThreadSanitizer::initializeCallbacks(Module &M) {
|
||||
IRB.getVoidTy());
|
||||
TsanIgnoreEnd =
|
||||
M.getOrInsertFunction("__tsan_ignore_thread_end", Attr, IRB.getVoidTy());
|
||||
OrdTy = IRB.getInt32Ty();
|
||||
IntegerType *OrdTy = IRB.getInt32Ty();
|
||||
for (size_t i = 0; i < kNumberOfAccessSizes; ++i) {
|
||||
const unsigned ByteSize = 1U << i;
|
||||
const unsigned BitSize = ByteSize * 8;
|
||||
@ -280,20 +296,6 @@ void ThreadSanitizer::initializeCallbacks(Module &M) {
|
||||
IRB.getInt8PtrTy(), IRB.getInt32Ty(), IntptrTy);
|
||||
}
|
||||
|
||||
ThreadSanitizer::ThreadSanitizer(Module &M) {
|
||||
const DataLayout &DL = M.getDataLayout();
|
||||
IntptrTy = DL.getIntPtrType(M.getContext());
|
||||
std::tie(TsanCtorFunction, std::ignore) =
|
||||
getOrCreateSanitizerCtorAndInitFunctions(
|
||||
M, kTsanModuleCtorName, kTsanInitName, /*InitArgTypes=*/{},
|
||||
/*InitArgs=*/{},
|
||||
// This callback is invoked when the functions are created the first
|
||||
// time. Hook them into the global ctors list in that case:
|
||||
[&](Function *Ctor, FunctionCallee) {
|
||||
appendToGlobalCtors(M, Ctor, 0);
|
||||
});
|
||||
}
|
||||
|
||||
static bool isVtableAccess(Instruction *I) {
|
||||
if (MDNode *Tag = I->getMetadata(LLVMContext::MD_tbaa))
|
||||
return Tag->isTBAAVtableAccess();
|
||||
@ -436,9 +438,9 @@ bool ThreadSanitizer::sanitizeFunction(Function &F,
|
||||
const TargetLibraryInfo &TLI) {
|
||||
// This is required to prevent instrumenting call to __tsan_init from within
|
||||
// the module constructor.
|
||||
if (&F == TsanCtorFunction)
|
||||
if (F.getName() == kTsanModuleCtorName)
|
||||
return false;
|
||||
initializeCallbacks(*F.getParent());
|
||||
initialize(*F.getParent());
|
||||
SmallVector<Instruction*, 8> AllLoadsAndStores;
|
||||
SmallVector<Instruction*, 8> LocalLoadsAndStores;
|
||||
SmallVector<Instruction*, 8> AtomicAccesses;
|
||||
|
@ -1,10 +1,9 @@
|
||||
; RUN: opt < %s -msan-check-access-address=0 -S -passes=msan 2>&1 | FileCheck \
|
||||
; RUN: -allow-deprecated-dag-overlap %s
|
||||
; RUN: opt < %s -msan -msan-check-access-address=0 -S | FileCheck -allow-deprecated-dag-overlap %s
|
||||
; RUN: opt < %s -msan-check-access-address=0 -msan-track-origins=1 -S \
|
||||
; RUN: -passes=msan 2>&1 | FileCheck -allow-deprecated-dag-overlap \
|
||||
; RUN: -check-prefix=CHECK -check-prefix=CHECK-ORIGINS %s
|
||||
; RUN: opt < %s -msan -msan-check-access-address=0 -msan-track-origins=1 -S | FileCheck -allow-deprecated-dag-overlap -check-prefix=CHECK -check-prefix=CHECK-ORIGINS %s
|
||||
; RUN: opt < %s -msan-check-access-address=0 -S -passes='module(msan-module),function(msan)' 2>&1 | FileCheck -allow-deprecated-dag-overlap %s
|
||||
; RUN: opt < %s --passes='module(msan-module),function(msan)' -msan-check-access-address=0 -S | FileCheck -allow-deprecated-dag-overlap %s
|
||||
; RUN: opt < %s -msan-check-access-address=0 -msan-track-origins=1 -S -passes='module(msan-module),function(msan)' 2>&1 | \
|
||||
; RUN: FileCheck -allow-deprecated-dag-overlap -check-prefixes=CHECK,CHECK-ORIGINS %s
|
||||
; RUN: opt < %s -passes='module(msan-module),function(msan)' -msan-check-access-address=0 -msan-track-origins=1 -S | \
|
||||
; RUN: FileCheck -allow-deprecated-dag-overlap -check-prefixes=CHECK,CHECK-ORIGINS %s
|
||||
|
||||
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-S128"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
@ -1,5 +1,5 @@
|
||||
; RUN: opt < %s -tsan -S | FileCheck %s
|
||||
; RUN: opt < %s -passes=tsan -S | FileCheck %s
|
||||
; RUN: opt < %s -passes='function(tsan),module(tsan-module)' -S | FileCheck %s
|
||||
|
||||
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"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
Loading…
x
Reference in New Issue
Block a user