52 #define DEBUG_TYPE "tsan"
55 "tsan-instrument-memory-accesses",
cl::init(
true),
58 "tsan-instrument-func-entry-exit",
cl::init(
true),
61 "tsan-handle-cxx-exceptions",
cl::init(
true),
62 cl::desc(
"Handle C++ exceptions (insert cleanup blocks for unwinding)"),
65 "tsan-instrument-atomics",
cl::init(
true),
68 "tsan-instrument-memintrinsics",
cl::init(
true),
71 STATISTIC(NumInstrumentedReads,
"Number of instrumented reads");
72 STATISTIC(NumInstrumentedWrites,
"Number of instrumented writes");
74 "Number of reads ignored due to following writes");
75 STATISTIC(NumAccessesWithBadSize,
"Number of accesses with bad size");
76 STATISTIC(NumInstrumentedVtableWrites,
"Number of vtable ptr writes");
77 STATISTIC(NumInstrumentedVtableReads,
"Number of vtable ptr reads");
78 STATISTIC(NumOmittedReadsFromConstantGlobals,
79 "Number of reads from constant globals");
80 STATISTIC(NumOmittedReadsFromVtable,
"Number of vtable reads");
81 STATISTIC(NumOmittedNonCaptured,
"Number of accesses ignored due to capturing");
94 bool doInitialization(
Module &M)
override;
98 void initializeCallbacks(
Module &M);
105 bool addrPointsToConstantData(
Value *Addr);
107 void InsertRuntimeIgnores(
Function &F);
130 Function *MemmoveFn, *MemcpyFn, *MemsetFn;
137 ThreadSanitizer,
"tsan",
138 "ThreadSanitizer: detects data races.",
143 "ThreadSanitizer: detects data races.",
146 StringRef ThreadSanitizer::getPassName()
const {
return "ThreadSanitizer"; }
148 void ThreadSanitizer::getAnalysisUsage(
AnalysisUsage &AU)
const {
153 return new ThreadSanitizer();
156 void ThreadSanitizer::initializeCallbacks(
Module &M) {
166 "__tsan_ignore_thread_begin", Attr, IRB.
getVoidTy(),
nullptr));
168 "__tsan_ignore_thread_end", Attr, IRB.
getVoidTy(),
nullptr));
169 OrdTy = IRB.getInt32Ty();
171 const unsigned ByteSize = 1U <<
i;
172 const unsigned BitSize = ByteSize * 8;
173 std::string ByteSizeStr =
utostr(ByteSize);
174 std::string BitSizeStr =
utostr(BitSize);
183 SmallString<64> UnalignedReadName(
"__tsan_unaligned_read" + ByteSizeStr);
184 TsanUnalignedRead[
i] =
188 SmallString<64> UnalignedWriteName(
"__tsan_unaligned_write" + ByteSizeStr);
189 TsanUnalignedWrite[
i] =
195 SmallString<32> AtomicLoadName(
"__tsan_atomic" + BitSizeStr +
"_load");
199 SmallString<32> AtomicStoreName(
"__tsan_atomic" + BitSizeStr +
"_store");
201 AtomicStoreName, Attr, IRB.
getVoidTy(), PtrTy, Ty, OrdTy,
nullptr));
205 TsanAtomicRMW[
op][
i] =
nullptr;
206 const char *NamePart =
nullptr;
208 NamePart =
"_exchange";
210 NamePart =
"_fetch_add";
212 NamePart =
"_fetch_sub";
214 NamePart =
"_fetch_and";
216 NamePart =
"_fetch_or";
218 NamePart =
"_fetch_xor";
220 NamePart =
"_fetch_nand";
229 "_compare_exchange_val");
231 AtomicCASName, Attr, Ty, PtrTy, Ty, Ty, OrdTy, OrdTy,
nullptr));
239 "__tsan_atomic_thread_fence", Attr, IRB.
getVoidTy(), OrdTy,
nullptr));
241 "__tsan_atomic_signal_fence", Attr, IRB.
getVoidTy(), OrdTy,
nullptr));
254 bool ThreadSanitizer::doInitialization(
Module &M) {
268 return Tag->isTBAAVtableAccess();
279 if (GV->hasSection()) {
288 if (GV->getName().startswith(
"__llvm_gcov") ||
289 GV->getName().startswith(
"__llvm_gcda"))
304 bool ThreadSanitizer::addrPointsToConstantData(
Value *Addr) {
307 Addr =
GEP->getPointerOperand();
310 if (GV->isConstant()) {
312 NumOmittedReadsFromConstantGlobals++;
315 }
else if (
LoadInst *
L = dyn_cast<LoadInst>(Addr)) {
318 NumOmittedReadsFromVtable++;
337 void ThreadSanitizer::chooseInstructionsToInstrument(
347 WriteTargets.
insert(Addr);
353 if (WriteTargets.
count(Addr)) {
355 NumOmittedReadsBeforeWrite++;
358 if (addrPointsToConstantData(Addr)) {
363 Value *Addr = isa<StoreInst>(*I)
371 NumOmittedNonCaptured++;
380 if (
LoadInst *LI = dyn_cast<LoadInst>(I))
381 return LI->isAtomic() && LI->getSynchScope() ==
CrossThread;
384 if (isa<AtomicRMWInst>(I))
386 if (isa<AtomicCmpXchgInst>(I))
388 if (isa<FenceInst>(I))
393 void ThreadSanitizer::InsertRuntimeIgnores(
Function &
F) {
398 AtExit->CreateCall(TsanIgnoreEnd);
402 bool ThreadSanitizer::runOnFunction(
Function &F) {
405 if (&F == TsanCtorFunction)
413 bool HasCalls =
false;
414 bool SanitizeFunction = F.
hasFnAttribute(Attribute::SanitizeThread);
417 &getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
421 for (
auto &Inst : BB) {
424 else if (isa<LoadInst>(Inst) || isa<StoreInst>(Inst))
426 else if (isa<CallInst>(Inst) || isa<InvokeInst>(Inst)) {
427 if (
CallInst *CI = dyn_cast<CallInst>(&Inst))
429 if (isa<MemIntrinsic>(Inst))
432 chooseInstructionsToInstrument(LocalLoadsAndStores, AllLoadsAndStores,
436 chooseInstructionsToInstrument(LocalLoadsAndStores, AllLoadsAndStores, DL);
445 for (
auto Inst : AllLoadsAndStores) {
446 Res |= instrumentLoadOrStore(Inst, DL);
452 for (
auto Inst : AtomicAccesses) {
453 Res |= instrumentAtomic(Inst, DL);
457 for (
auto Inst : MemIntrinCalls) {
458 Res |= instrumentMemIntrinsic(Inst);
461 if (F.hasFnAttribute(
"sanitize_thread_no_checking_at_run_time")) {
462 assert(!F.hasFnAttribute(Attribute::SanitizeThread));
464 InsertRuntimeIgnores(F);
469 IRBuilder<> IRB(F.getEntryBlock().getFirstNonPHI());
470 Value *ReturnAddress = IRB.CreateCall(
473 IRB.CreateCall(TsanFuncEntry, ReturnAddress);
477 AtExit->CreateCall(TsanFuncExit, {});
484 bool ThreadSanitizer::instrumentLoadOrStore(
Instruction *
I,
487 bool IsWrite = isa<StoreInst>(*I);
488 Value *Addr = IsWrite
498 int Idx = getMemoryAccessFuncIndex(Addr, DL);
502 DEBUG(
dbgs() <<
" VPTR : " << *I <<
"\n");
503 Value *StoredValue = cast<StoreInst>(
I)->getValueOperand();
507 if (isa<VectorType>(StoredValue->
getType()))
508 StoredValue = IRB.CreateExtractElement(
511 StoredValue = IRB.CreateIntToPtr(StoredValue, IRB.getInt8PtrTy());
513 IRB.CreateCall(TsanVptrUpdate,
514 {IRB.CreatePointerCast(Addr, IRB.getInt8PtrTy()),
515 IRB.CreatePointerCast(StoredValue, IRB.getInt8PtrTy())});
516 NumInstrumentedVtableWrites++;
520 IRB.CreateCall(TsanVptrLoad,
521 IRB.CreatePointerCast(Addr, IRB.getInt8PtrTy()));
522 NumInstrumentedVtableReads++;
525 const unsigned Alignment = IsWrite
528 Type *OrigTy = cast<PointerType>(Addr->
getType())->getElementType();
530 Value *OnAccessFunc =
nullptr;
531 if (Alignment == 0 || Alignment >= 8 || (Alignment % (TypeSize / 8)) == 0)
532 OnAccessFunc = IsWrite ? TsanWrite[Idx] : TsanRead[Idx];
534 OnAccessFunc = IsWrite ? TsanUnalignedWrite[Idx] : TsanUnalignedRead[Idx];
535 IRB.CreateCall(OnAccessFunc, IRB.CreatePointerCast(Addr, IRB.getInt8PtrTy()));
536 if (IsWrite) NumInstrumentedWrites++;
537 else NumInstrumentedReads++;
566 bool ThreadSanitizer::instrumentMemIntrinsic(
Instruction *I) {
568 if (
MemSetInst *M = dyn_cast<MemSetInst>(I)) {
571 {IRB.CreatePointerCast(M->getArgOperand(0), IRB.getInt8PtrTy()),
572 IRB.CreateIntCast(M->getArgOperand(1), IRB.getInt32Ty(),
false),
573 IRB.CreateIntCast(M->getArgOperand(2), IntptrTy,
false)});
577 isa<MemCpyInst>(M) ? MemcpyFn : MemmoveFn,
578 {IRB.CreatePointerCast(M->getArgOperand(0), IRB.getInt8PtrTy()),
579 IRB.CreatePointerCast(M->getArgOperand(1), IRB.getInt8PtrTy()),
580 IRB.CreateIntCast(M->getArgOperand(2), IntptrTy,
false)});
596 if (
LoadInst *LI = dyn_cast<LoadInst>(I)) {
597 Value *Addr = LI->getPointerOperand();
598 int Idx = getMemoryAccessFuncIndex(Addr, DL);
601 const unsigned ByteSize = 1U << Idx;
602 const unsigned BitSize = ByteSize * 8;
605 Value *
Args[] = {IRB.CreatePointerCast(Addr, PtrTy),
607 Type *OrigTy = cast<PointerType>(Addr->
getType())->getElementType();
608 Value *
C = IRB.CreateCall(TsanAtomicLoad[Idx], Args);
609 Value *Cast = IRB.CreateBitOrPointerCast(C, OrigTy);
611 }
else if (
StoreInst *SI = dyn_cast<StoreInst>(I)) {
612 Value *Addr =
SI->getPointerOperand();
613 int Idx = getMemoryAccessFuncIndex(Addr, DL);
616 const unsigned ByteSize = 1U << Idx;
617 const unsigned BitSize = ByteSize * 8;
620 Value *Args[] = {IRB.CreatePointerCast(Addr, PtrTy),
621 IRB.CreateBitOrPointerCast(
SI->getValueOperand(), Ty),
625 }
else if (
AtomicRMWInst *RMWI = dyn_cast<AtomicRMWInst>(I)) {
626 Value *Addr = RMWI->getPointerOperand();
627 int Idx = getMemoryAccessFuncIndex(Addr, DL);
630 Function *F = TsanAtomicRMW[RMWI->getOperation()][Idx];
633 const unsigned ByteSize = 1U << Idx;
634 const unsigned BitSize = ByteSize * 8;
637 Value *Args[] = {IRB.CreatePointerCast(Addr, PtrTy),
638 IRB.CreateIntCast(RMWI->getValOperand(), Ty,
false),
643 Value *Addr = CASI->getPointerOperand();
644 int Idx = getMemoryAccessFuncIndex(Addr, DL);
647 const unsigned ByteSize = 1U << Idx;
648 const unsigned BitSize = ByteSize * 8;
652 IRB.CreateBitOrPointerCast(CASI->getCompareOperand(), Ty);
654 IRB.CreateBitOrPointerCast(CASI->getNewValOperand(), Ty);
655 Value *Args[] = {IRB.CreatePointerCast(Addr, PtrTy),
660 CallInst *C = IRB.CreateCall(TsanAtomicCAS[Idx], Args);
663 Type *OrigOldValTy = CASI->getNewValOperand()->getType();
664 if (Ty != OrigOldValTy) {
666 OldVal = IRB.CreateIntToPtr(C, OrigOldValTy);
671 Res = IRB.CreateInsertValue(Res, Success, 1);
675 }
else if (
FenceInst *FI = dyn_cast<FenceInst>(I)) {
678 TsanAtomicSignalFence : TsanAtomicThreadFence;
685 int ThreadSanitizer::getMemoryAccessFuncIndex(
Value *Addr,
688 Type *OrigTy = cast<PointerType>(OrigPtrTy)->getElementType();
691 if (TypeSize != 8 && TypeSize != 16 &&
692 TypeSize != 32 && TypeSize != 64 && TypeSize != 128) {
693 NumAccessesWithBadSize++;
698 assert(Idx < kNumberOfAccessSizes);
SymbolTableList< Instruction >::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
void push_back(const T &Elt)
A parsed version of the target data layout string in and methods for querying it. ...
void ReplaceInstWithInst(BasicBlock::InstListType &BIL, BasicBlock::iterator &BI, Instruction *I)
Replace the instruction specified by BI with the instruction specified by I.
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE bool endswith(StringRef Suffix) const
Check if this string ends with the given Suffix.
Function * checkSanitizerInterfaceFunction(Constant *FuncOrBitcast)
STATISTIC(NumFunctions,"Total number of functions")
A Module instance is used to store all the information related to an LLVM module. ...
An instruction for ordering other memory operations.
an instruction that atomically checks whether a specified value is in a memory location, and, if it is, stores a new value there.
This class represents a function call, abstracting a target machine's calling convention.
This class wraps the llvm.memset intrinsic.
An instruction for reading from memory.
an instruction that atomically reads a memory location, combines it with another value, and then stores the result back.
static cl::opt< bool > ClInstrumentAtomics("tsan-instrument-atomics", cl::init(true), cl::desc("Instrument atomics"), cl::Hidden)
EscapeEnumerator - This is a little algorithm to find all escape points from a function so that "fina...
AnalysisUsage & addRequired()
#define INITIALIZE_PASS_DEPENDENCY(depName)
static Value * getPointerOperand(Instruction &Inst)
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Instruction * getFirstNonPHI()
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Type * getVoidTy()
Fetch the type representing void.
AtomicOrdering
Atomic ordering for LLVM's memory model.
auto reverse(ContainerTy &&C, typename std::enable_if< has_rbegin< ContainerTy >::value >::type *=nullptr) -> decltype(make_range(C.rbegin(), C.rend()))
static unsigned getAlignment(GlobalVariable *GV)
static std::string utostr(uint64_t X, bool isNeg=false)
Function * getDeclaration(Module *M, ID id, ArrayRef< Type * > Tys=None)
Create or insert an LLVM Function declaration for an intrinsic, and return it.
An instruction for storing to memory.
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Type * getScalarType() const LLVM_READONLY
If this is a vector type, return the element type, otherwise return 'this'.
std::enable_if<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type cast(const Y &Val)
bool isSized(SmallPtrSetImpl< Type * > *Visited=nullptr) const
Return true if it makes sense to take the size of this type.
an instruction for type-safe pointer arithmetic to access elements of arrays and structs ...
static const size_t kNumberOfAccessSizes
initializer< Ty > init(const Ty &Val)
std::size_t countTrailingZeros(T Val, ZeroBehavior ZB=ZB_Width)
Count number of 0's from the least significant bit to the most stopping at the first 1...
Constant * getOrInsertFunction(StringRef Name, FunctionType *T, AttributeSet AttributeList)
Look up the specified function in the module symbol table.
The instances of the Type class are immutable: once they are created, they are never changed...
uint64_t getTypeStoreSizeInBits(Type *Ty) const
Returns the maximum number of bits that may be overwritten by storing the specified type; always a mu...
static const char *const kTsanModuleCtorName
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
Value * stripInBoundsOffsets()
Strip off pointer casts and inbounds GEPs.
Represent the analysis usage information of a pass.
INITIALIZE_PASS_END(RegBankSelect, DEBUG_TYPE,"Assign register bank of generic virtual registers", false, false) RegBankSelect
FunctionPass * createThreadSanitizerPass()
FunctionPass class - This class is used to implement most global optimizations.
Value * getPointerOperand()
Class to represent integer types.
std::pair< NoneType, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
static UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
static std::string itostr(int64_t X)
static cl::opt< bool > ClInstrumentFuncEntryExit("tsan-instrument-func-entry-exit", cl::init(true), cl::desc("Instrument function entry and exit"), cl::Hidden)
bool PointerMayBeCaptured(const Value *V, bool ReturnCaptures, bool StoreCaptures)
PointerMayBeCaptured - Return true if this pointer value may be captured by the enclosing function (w...
static bool isAtomic(Instruction *I)
PointerType * getInt8PtrTy(unsigned AddrSpace=0)
Fetch the type representing a pointer to an 8-bit integer value.
static PointerType * getInt8PtrTy(LLVMContext &C, unsigned AS=0)
Value * GetUnderlyingObject(Value *V, const DataLayout &DL, unsigned MaxLookup=6)
This method strips off any GEP address adjustments and pointer casts from the specified value...
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
size_type count(const T &V) const
count - Return 1 if the element is in the set, 0 otherwise.
IntegerType * getIntPtrType(LLVMContext &C, unsigned AddressSpace=0) const
Returns an integer type with size at least as big as that of a pointer in the given address space...
std::pair< Function *, Function * > createSanitizerCtorAndInitFunctions(Module &M, StringRef CtorName, StringRef InitName, ArrayRef< Type * > InitArgTypes, ArrayRef< Value * > InitArgs, StringRef VersionCheckName=StringRef())
Creates sanitizer constructor function, and calls sanitizer's init function from it.
This is the shared class of boolean and integer constants.
static CallInst * Create(Value *Func, ArrayRef< Value * > Args, ArrayRef< OperandBundleDef > Bundles=None, const Twine &NameStr="", Instruction *InsertBefore=nullptr)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
Module.h This file contains the declarations for the Module class.
Type * getType() const
All values are typed, get the type of this value.
Provides information about what library functions are available for the current target.
MDNode * getMetadata(unsigned KindID) const
Get the metadata of given kind attached to this Instruction.
bool isSwiftError() const
Return true if this value is a swifterror value.
ConstantInt * getInt32(uint32_t C)
Get a constant 32-bit value.
static IntegerType * getIntNTy(LLVMContext &C, unsigned N)
static Constant * get(Type *Ty, uint64_t V, bool isSigned=false)
If Ty is a vector type, return a Constant with a splat of the given value.
static ConstantInt * createOrdering(IRBuilder<> *IRB, AtomicOrdering ord)
void appendToGlobalCtors(Module &M, Function *F, int Priority, Constant *Data=nullptr)
Append F to the list of global ctors of module M with the given Priority.
const BasicBlock & getEntryBlock() const
static GCRegistry::Add< ShadowStackGC > C("shadow-stack","Very portable GC for uncooperative code generators")
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool isIntegerTy() const
True if this is an instance of IntegerType.
static cl::opt< bool > ClHandleCxxExceptions("tsan-handle-cxx-exceptions", cl::init(true), cl::desc("Handle C++ exceptions (insert cleanup blocks for unwinding)"), cl::Hidden)
static bool shouldInstrumentReadWriteFromAddress(Value *Addr)
This class wraps the llvm.memcpy/memmove intrinsics.
const DataLayout & getDataLayout() const
Get the data layout for the module's target platform.
INITIALIZE_PASS_BEGIN(ThreadSanitizer,"tsan","ThreadSanitizer: detects data races.", false, false) INITIALIZE_PASS_END(ThreadSanitizer
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
StringRef getInstrProfCountersSectionName(bool AddSegment)
Return the name of data section containing profile counter variables.
static IntegerType * getInt32Ty(LLVMContext &C)
static cl::opt< bool > ClInstrumentMemoryAccesses("tsan-instrument-memory-accesses", cl::init(true), cl::desc("Instrument memory accesses"), cl::Hidden)
CallInst * CreateCall(Value *Callee, ArrayRef< Value * > Args=None, const Twine &Name="", MDNode *FPMathTag=nullptr)
void maybeMarkSanitizerLibraryCallNoBuiltin(CallInst *CI, const TargetLibraryInfo *TLI)
Given a CallInst, check if it calls a string function known to CodeGen, and mark it with NoBuiltin if...
static cl::opt< bool > ClInstrumentMemIntrinsics("tsan-instrument-memintrinsics", cl::init(true), cl::desc("Instrument memintrinsics (memset/memcpy/memmove)"), cl::Hidden)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static const char *const kTsanInitName
Module * getParent()
Get the module that this global value is contained inside of...
LLVM Value Representation.
#define LLVM_FALLTHROUGH
LLVM_FALLTHROUGH - Mark fallthrough cases in switch statements.
PointerType * getPointerTo(unsigned AddrSpace=0) const
Return a pointer to the current type.
StringRef - Represent a constant reference to a string, i.e.
unsigned getPointerAddressSpace() const
Get the address space of this pointer or pointer vector type.
static bool isVtableAccess(Instruction *I)
LLVMContext & getContext() const
Get the global data context.