48 #define DEBUG_TYPE "tsan"
51 "tsan-instrument-memory-accesses",
cl::init(
true),
54 "tsan-instrument-func-entry-exit",
cl::init(
true),
57 "tsan-instrument-atomics",
cl::init(
true),
60 "tsan-instrument-memintrinsics",
cl::init(
true),
63 STATISTIC(NumInstrumentedReads,
"Number of instrumented reads");
64 STATISTIC(NumInstrumentedWrites,
"Number of instrumented writes");
66 "Number of reads ignored due to following writes");
67 STATISTIC(NumAccessesWithBadSize,
"Number of accesses with bad size");
68 STATISTIC(NumInstrumentedVtableWrites,
"Number of vtable ptr writes");
69 STATISTIC(NumInstrumentedVtableReads,
"Number of vtable ptr reads");
70 STATISTIC(NumOmittedReadsFromConstantGlobals,
71 "Number of reads from constant globals");
72 STATISTIC(NumOmittedReadsFromVtable,
"Number of vtable reads");
73 STATISTIC(NumOmittedNonCaptured,
"Number of accesses ignored due to capturing");
83 const char *getPassName()
const override;
85 bool doInitialization(
Module &M)
override;
89 void initializeCallbacks(
Module &M);
96 bool addrPointsToConstantData(
Value *Addr);
118 Function *MemmoveFn, *MemcpyFn, *MemsetFn;
125 "ThreadSanitizer: detects data races.",
128 const char *ThreadSanitizer::getPassName()
const {
129 return "ThreadSanitizer";
133 return new ThreadSanitizer();
136 void ThreadSanitizer::initializeCallbacks(
Module &M) {
140 "__tsan_func_entry", IRB.getVoidTy(), IRB.getInt8PtrTy(),
nullptr));
143 OrdTy = IRB.getInt32Ty();
145 const size_t ByteSize = 1 << i;
146 const size_t BitSize = ByteSize * 8;
149 ReadName, IRB.getVoidTy(), IRB.getInt8PtrTy(),
nullptr));
153 WriteName, IRB.getVoidTy(), IRB.getInt8PtrTy(),
nullptr));
157 TsanUnalignedRead[i] =
159 UnalignedReadName, IRB.getVoidTy(), IRB.getInt8PtrTy(),
nullptr));
163 TsanUnalignedWrite[i] =
165 UnalignedWriteName, IRB.getVoidTy(), IRB.getInt8PtrTy(),
nullptr));
177 AtomicStoreName, IRB.getVoidTy(), PtrTy, Ty, OrdTy,
nullptr));
181 TsanAtomicRMW[
op][i] =
nullptr;
182 const char *NamePart =
nullptr;
184 NamePart =
"_exchange";
186 NamePart =
"_fetch_add";
188 NamePart =
"_fetch_sub";
190 NamePart =
"_fetch_and";
192 NamePart =
"_fetch_or";
194 NamePart =
"_fetch_xor";
196 NamePart =
"_fetch_nand";
205 "_compare_exchange_val");
207 AtomicCASName, Ty, PtrTy, Ty, Ty, OrdTy, OrdTy,
nullptr));
211 IRB.getInt8PtrTy(), IRB.getInt8PtrTy(),
nullptr));
213 "__tsan_vptr_read", IRB.getVoidTy(), IRB.getInt8PtrTy(),
nullptr));
215 "__tsan_atomic_thread_fence", IRB.getVoidTy(), OrdTy,
nullptr));
217 "__tsan_atomic_signal_fence", IRB.getVoidTy(), OrdTy,
nullptr));
221 IRB.getInt8PtrTy(), IntptrTy,
nullptr));
224 IRB.getInt8PtrTy(), IntptrTy,
nullptr));
227 IRB.getInt32Ty(), IntptrTy,
nullptr));
230 bool ThreadSanitizer::doInitialization(
Module &M) {
244 return Tag->isTBAAVtableAccess();
248 bool ThreadSanitizer::addrPointsToConstantData(
Value *Addr) {
251 Addr =
GEP->getPointerOperand();
254 if (GV->isConstant()) {
256 NumOmittedReadsFromConstantGlobals++;
259 }
else if (
LoadInst *L = dyn_cast<LoadInst>(Addr)) {
262 NumOmittedReadsFromVtable++;
281 void ThreadSanitizer::chooseInstructionsToInstrument(
287 E = Local.
rend(); It != E; ++It) {
294 if (WriteTargets.
count(Addr)) {
296 NumOmittedReadsBeforeWrite++;
299 if (addrPointsToConstantData(Addr)) {
304 Value *Addr = isa<StoreInst>(*I)
312 NumOmittedNonCaptured++;
321 if (
LoadInst *LI = dyn_cast<LoadInst>(I))
322 return LI->isAtomic() && LI->getSynchScope() ==
CrossThread;
325 if (isa<AtomicRMWInst>(I))
327 if (isa<AtomicCmpXchgInst>(I))
329 if (isa<FenceInst>(I))
334 bool ThreadSanitizer::runOnFunction(
Function &
F) {
337 if (&F == TsanCtorFunction)
346 bool HasCalls =
false;
352 for (
auto &Inst : BB) {
355 else if (isa<LoadInst>(Inst) || isa<StoreInst>(Inst))
357 else if (isa<ReturnInst>(Inst))
358 RetVec.push_back(&Inst);
359 else if (isa<CallInst>(Inst) || isa<InvokeInst>(Inst)) {
360 if (isa<MemIntrinsic>(Inst))
363 chooseInstructionsToInstrument(LocalLoadsAndStores, AllLoadsAndStores,
367 chooseInstructionsToInstrument(LocalLoadsAndStores, AllLoadsAndStores, DL);
376 for (
auto Inst : AllLoadsAndStores) {
377 Res |= instrumentLoadOrStore(Inst, DL);
383 for (
auto Inst : AtomicAccesses) {
384 Res |= instrumentAtomic(Inst, DL);
388 for (
auto Inst : MemIntrinCalls) {
389 Res |= instrumentMemIntrinsic(Inst);
394 IRBuilder<> IRB(F.getEntryBlock().getFirstNonPHI());
395 Value *ReturnAddress = IRB.CreateCall(
398 IRB.CreateCall(TsanFuncEntry, ReturnAddress);
399 for (
auto RetInst : RetVec) {
401 IRBRet.CreateCall(TsanFuncExit, {});
408 bool ThreadSanitizer::instrumentLoadOrStore(
Instruction *I,
411 bool IsWrite = isa<StoreInst>(*I);
412 Value *Addr = IsWrite
415 int Idx = getMemoryAccessFuncIndex(Addr, DL);
419 DEBUG(
dbgs() <<
" VPTR : " << *I <<
"\n");
420 Value *StoredValue = cast<StoreInst>(
I)->getValueOperand();
424 if (isa<VectorType>(StoredValue->
getType()))
425 StoredValue = IRB.CreateExtractElement(
428 StoredValue = IRB.CreateIntToPtr(StoredValue, IRB.getInt8PtrTy());
430 IRB.CreateCall(TsanVptrUpdate,
431 {IRB.CreatePointerCast(Addr, IRB.getInt8PtrTy()),
432 IRB.CreatePointerCast(StoredValue, IRB.getInt8PtrTy())});
433 NumInstrumentedVtableWrites++;
437 IRB.CreateCall(TsanVptrLoad,
438 IRB.CreatePointerCast(Addr, IRB.getInt8PtrTy()));
439 NumInstrumentedVtableReads++;
442 const unsigned Alignment = IsWrite
443 ? cast<StoreInst>(
I)->getAlignment()
445 Type *OrigTy = cast<PointerType>(Addr->
getType())->getElementType();
447 Value *OnAccessFunc =
nullptr;
448 if (Alignment == 0 || Alignment >= 8 || (Alignment % (TypeSize / 8)) == 0)
449 OnAccessFunc = IsWrite ? TsanWrite[Idx] : TsanRead[Idx];
451 OnAccessFunc = IsWrite ? TsanUnalignedWrite[Idx] : TsanUnalignedRead[Idx];
452 IRB.CreateCall(OnAccessFunc, IRB.CreatePointerCast(Addr, IRB.getInt8PtrTy()));
453 if (IsWrite) NumInstrumentedWrites++;
454 else NumInstrumentedReads++;
481 bool ThreadSanitizer::instrumentMemIntrinsic(
Instruction *I) {
483 if (
MemSetInst *M = dyn_cast<MemSetInst>(I)) {
486 {IRB.CreatePointerCast(M->getArgOperand(0), IRB.getInt8PtrTy()),
487 IRB.CreateIntCast(M->getArgOperand(1), IRB.getInt32Ty(),
false),
488 IRB.CreateIntCast(M->getArgOperand(2), IntptrTy,
false)});
492 isa<MemCpyInst>(M) ? MemcpyFn : MemmoveFn,
493 {IRB.CreatePointerCast(M->getArgOperand(0), IRB.getInt8PtrTy()),
494 IRB.CreatePointerCast(M->getArgOperand(1), IRB.getInt8PtrTy()),
495 IRB.CreateIntCast(M->getArgOperand(2), IntptrTy,
false)});
511 if (
LoadInst *LI = dyn_cast<LoadInst>(I)) {
512 Value *Addr = LI->getPointerOperand();
513 int Idx = getMemoryAccessFuncIndex(Addr, DL);
516 const size_t ByteSize = 1 << Idx;
517 const size_t BitSize = ByteSize * 8;
520 Value *Args[] = {IRB.CreatePointerCast(Addr, PtrTy),
525 }
else if (
StoreInst *SI = dyn_cast<StoreInst>(I)) {
526 Value *Addr =
SI->getPointerOperand();
527 int Idx = getMemoryAccessFuncIndex(Addr, DL);
530 const size_t ByteSize = 1 << Idx;
531 const size_t BitSize = ByteSize * 8;
534 Value *Args[] = {IRB.CreatePointerCast(Addr, PtrTy),
535 IRB.CreateIntCast(
SI->getValueOperand(), Ty,
false),
539 }
else if (
AtomicRMWInst *RMWI = dyn_cast<AtomicRMWInst>(I)) {
540 Value *Addr = RMWI->getPointerOperand();
541 int Idx = getMemoryAccessFuncIndex(Addr, DL);
544 Function *F = TsanAtomicRMW[RMWI->getOperation()][Idx];
547 const size_t ByteSize = 1 << Idx;
548 const size_t BitSize = ByteSize * 8;
551 Value *Args[] = {IRB.CreatePointerCast(Addr, PtrTy),
552 IRB.CreateIntCast(RMWI->getValOperand(), Ty,
false),
557 Value *Addr = CASI->getPointerOperand();
558 int Idx = getMemoryAccessFuncIndex(Addr, DL);
561 const size_t ByteSize = 1 << Idx;
562 const size_t BitSize = ByteSize * 8;
565 Value *Args[] = {IRB.CreatePointerCast(Addr, PtrTy),
566 IRB.CreateIntCast(CASI->getCompareOperand(), Ty,
false),
567 IRB.CreateIntCast(CASI->getNewValOperand(), Ty,
false),
570 CallInst *
C = IRB.CreateCall(TsanAtomicCAS[Idx], Args);
571 Value *
Success = IRB.CreateICmpEQ(C, CASI->getCompareOperand());
574 Res = IRB.CreateInsertValue(Res, Success, 1);
578 }
else if (
FenceInst *FI = dyn_cast<FenceInst>(I)) {
581 TsanAtomicSignalFence : TsanAtomicThreadFence;
588 int ThreadSanitizer::getMemoryAccessFuncIndex(
Value *Addr,
591 Type *OrigTy = cast<PointerType>(OrigPtrTy)->getElementType();
594 if (TypeSize != 8 && TypeSize != 16 &&
595 TypeSize != 32 && TypeSize != 64 && TypeSize != 128) {
596 NumAccessesWithBadSize++;
601 assert(Idx < kNumberOfAccessSizes);
iplist< Instruction >::iterator eraseFromParent()
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)
ReplaceInstWithInst - Replace the instruction specified by BI with the instruction specified by I...
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. ...
FenceInst - an instruction for ordering other memory operations.
AtomicCmpXchgInst - an instruction that atomically checks whether a specified value is in a memory lo...
void appendToGlobalCtors(Module &M, Function *F, int Priority)
Append F to the list of global ctors of module M with the given Priority.
CallInst - This class represents a function call, abstracting a target machine's calling convention...
MemSetInst - This class wraps the llvm.memset intrinsic.
LoadInst - an instruction for reading from memory.
AtomicRMWInst - an instruction that atomically reads a memory location, combines it with another valu...
static cl::opt< bool > ClInstrumentAtomics("tsan-instrument-atomics", cl::init(true), cl::desc("Instrument atomics"), cl::Hidden)
static Value * getPointerOperand(Instruction &Inst)
static CallInst * Create(Value *Func, ArrayRef< Value * > Args, const Twine &NameStr="", Instruction *InsertBefore=nullptr)
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
bool isSized(SmallPtrSetImpl< const Type * > *Visited=nullptr) const
isSized - Return true if it makes sense to take the size of this type.
FunctionPass * createThreadSanitizerPass()
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Function * getDeclaration(Module *M, ID id, ArrayRef< Type * > Tys=None)
Create or insert an LLVM Function declaration for an intrinsic, and return it.
StoreInst - an instruction for storing to memory.
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
std::enable_if<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type cast(const Y &Val)
GetElementPtrInst - an instruction for type-safe pointer arithmetic to access elements of arrays and ...
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...
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)
get() - 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 * getPointerTo(unsigned AddrSpace=0)
getPointerTo - Return a pointer to the current type.
Value * GetUnderlyingObject(Value *V, const DataLayout &DL, unsigned MaxLookup=6)
GetUnderlyingObject - This method strips off any GEP address adjustments and pointer casts from the s...
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
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...
This is the shared class of boolean and integer constants.
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.
MDNode * getMetadata(unsigned KindID) const
getMetadata - Get the metadata of given kind attached to this Instruction.
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)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool isIntegerTy() const
isIntegerTy - True if this is an instance of IntegerType.
MemTransferInst - This class wraps the llvm.memcpy/memmove intrinsics.
const DataLayout & getDataLayout() const
Get the data layout for the module's target platform.
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
static cl::opt< bool > ClInstrumentMemoryAccesses("tsan-instrument-memory-accesses", cl::init(true), cl::desc("Instrument memory accesses"), cl::Hidden)
std::pair< Function *, Function * > createSanitizerCtorAndInitFunctions(Module &M, StringRef CtorName, StringRef InitName, ArrayRef< Type * > InitArgTypes, ArrayRef< Value * > InitArgs)
Creates sanitizer constructor function, and calls sanitizer's init function from it.
static cl::opt< bool > ClInstrumentMemIntrinsics("tsan-instrument-memintrinsics", cl::init(true), cl::desc("Instrument memintrinsics (memset/memcpy/memmove)"), cl::Hidden)
reverse_iterator rbegin()
static const char *const kTsanInitName
Module * getParent()
Get the module that this global value is contained inside of...
LLVM Value Representation.
C - The default llvm calling convention, compatible with C.
static bool isVtableAccess(Instruction *I)
LLVMContext & getContext() const
Get the global data context.