51#define DEBUG_TYPE "tsan"
53STATISTIC(NumInstrumentedReads,
"Number of instrumented reads");
54STATISTIC(NumInstrumentedWrites,
"Number of instrumented writes");
56 "Number of reads ignored due to following writes");
57STATISTIC(NumAccessesWithBadSize,
"Number of accesses with bad size");
58STATISTIC(NumInstrumentedVtableWrites,
"Number of vtable ptr writes");
59STATISTIC(NumInstrumentedVtableReads,
"Number of vtable ptr reads");
61 "Number of reads from constant globals");
62STATISTIC(NumOmittedReadsFromVtable,
"Number of vtable reads");
63STATISTIC(NumOmittedNonCaptured,
"Number of accesses ignored due to capturing");
76struct ThreadSanitizer {
77 ThreadSanitizer(
const InstrumentationOptions &Opts) : Opts(Opts) {
79 if (Opts.tsan_instrument_read_before_write &&
80 Opts.tsan_compound_read_before_write) {
82 <<
"warning: Option -tsan-compound-read-before-write has no effect "
83 "when -tsan-instrument-read-before-write is set.\n";
92 struct InstructionInfo {
95 static constexpr unsigned kCompoundRW = (1U << 0);
97 explicit InstructionInfo(
Instruction *Inst) : Inst(Inst) {}
104 bool instrumentLoadOrStore(
const InstructionInfo &
II,
const DataLayout &
DL);
110 bool addrPointsToConstantData(
Value *Addr);
114 const InstrumentationOptions &Opts;
156 ThreadSanitizer TSan(
157 F.getContext().getLibraryOptions().get<InstrumentationOptions>());
174 IntptrTy =
DL.getIntPtrType(Ctx);
178 Attr = Attr.addFnAttribute(Ctx, Attribute::NoUnwind);
180 TsanFuncEntry = M.getOrInsertFunction(
"__tsan_func_entry", Attr,
181 IRB.getVoidTy(), IRB.getPtrTy());
183 M.getOrInsertFunction(
"__tsan_func_exit", Attr, IRB.getVoidTy());
184 TsanIgnoreBegin = M.getOrInsertFunction(
"__tsan_ignore_thread_begin", Attr,
187 M.getOrInsertFunction(
"__tsan_ignore_thread_end", Attr, IRB.getVoidTy());
190 const unsigned ByteSize = 1U << i;
191 const unsigned BitSize = ByteSize * 8;
192 std::string ByteSizeStr =
utostr(ByteSize);
193 std::string BitSizeStr =
utostr(BitSize);
195 TsanRead[i] = M.getOrInsertFunction(ReadName, Attr, IRB.getVoidTy(),
199 TsanWrite[i] = M.getOrInsertFunction(WriteName, Attr, IRB.getVoidTy(),
202 SmallString<64> UnalignedReadName(
"__tsan_unaligned_read" + ByteSizeStr);
203 TsanUnalignedRead[i] = M.getOrInsertFunction(
204 UnalignedReadName, Attr, IRB.getVoidTy(), IRB.getPtrTy());
206 SmallString<64> UnalignedWriteName(
"__tsan_unaligned_write" + ByteSizeStr);
207 TsanUnalignedWrite[i] = M.getOrInsertFunction(
208 UnalignedWriteName, Attr, IRB.getVoidTy(), IRB.getPtrTy());
210 SmallString<64> VolatileReadName(
"__tsan_volatile_read" + ByteSizeStr);
211 TsanVolatileRead[i] = M.getOrInsertFunction(
212 VolatileReadName, Attr, IRB.getVoidTy(), IRB.getPtrTy());
214 SmallString<64> VolatileWriteName(
"__tsan_volatile_write" + ByteSizeStr);
215 TsanVolatileWrite[i] = M.getOrInsertFunction(
216 VolatileWriteName, Attr, IRB.getVoidTy(), IRB.getPtrTy());
218 SmallString<64> UnalignedVolatileReadName(
"__tsan_unaligned_volatile_read" +
220 TsanUnalignedVolatileRead[i] = M.getOrInsertFunction(
221 UnalignedVolatileReadName, Attr, IRB.getVoidTy(), IRB.getPtrTy());
224 "__tsan_unaligned_volatile_write" + ByteSizeStr);
225 TsanUnalignedVolatileWrite[i] = M.getOrInsertFunction(
226 UnalignedVolatileWriteName, Attr, IRB.getVoidTy(), IRB.getPtrTy());
229 TsanCompoundRW[i] = M.getOrInsertFunction(
230 CompoundRWName, Attr, IRB.getVoidTy(), IRB.getPtrTy());
232 SmallString<64> UnalignedCompoundRWName(
"__tsan_unaligned_read_write" +
234 TsanUnalignedCompoundRW[i] = M.getOrInsertFunction(
235 UnalignedCompoundRWName, Attr, IRB.getVoidTy(), IRB.getPtrTy());
239 SmallString<32> AtomicLoadName(
"__tsan_atomic" + BitSizeStr +
"_load");
241 M.getOrInsertFunction(AtomicLoadName,
243 BitSize <= 32, Attr),
247 using Idxs = std::vector<unsigned>;
248 Idxs Idxs2Or12 ((BitSize <= 32) ? Idxs({1, 2}) : Idxs({2}));
249 Idxs Idxs34Or1234((BitSize <= 32) ? Idxs({1, 2, 3, 4}) : Idxs({3, 4}));
250 SmallString<32> AtomicStoreName(
"__tsan_atomic" + BitSizeStr +
"_store");
251 TsanAtomicStore[i] =
M.getOrInsertFunction(
253 TLI.
getAttrList(&Ctx, Idxs2Or12,
true,
false, Attr),
254 IRB.getVoidTy(), PtrTy, Ty, OrdTy);
258 TsanAtomicRMW[
Op][i] =
nullptr;
259 const char *NamePart =
nullptr;
261 NamePart =
"_exchange";
263 NamePart =
"_fetch_add";
265 NamePart =
"_fetch_sub";
267 NamePart =
"_fetch_and";
269 NamePart =
"_fetch_or";
271 NamePart =
"_fetch_xor";
273 NamePart =
"_fetch_nand";
277 TsanAtomicRMW[
Op][i] =
M.getOrInsertFunction(
280 BitSize <= 32, Attr),
281 Ty, PtrTy, Ty, OrdTy);
285 "_compare_exchange_val");
286 TsanAtomicCAS[i] =
M.getOrInsertFunction(
289 BitSize <= 32, Attr),
290 Ty, PtrTy, Ty, Ty, OrdTy, OrdTy);
293 M.getOrInsertFunction(
"__tsan_vptr_update", Attr, IRB.getVoidTy(),
294 IRB.getPtrTy(), IRB.getPtrTy());
295 TsanVptrLoad =
M.getOrInsertFunction(
"__tsan_vptr_read", Attr,
296 IRB.getVoidTy(), IRB.getPtrTy());
297 TsanAtomicThreadFence =
M.getOrInsertFunction(
298 "__tsan_atomic_thread_fence",
300 IRB.getVoidTy(), OrdTy);
302 TsanAtomicSignalFence =
M.getOrInsertFunction(
303 "__tsan_atomic_signal_fence",
305 IRB.getVoidTy(), OrdTy);
308 M.getOrInsertFunction(
"__tsan_memmove", Attr, IRB.getPtrTy(),
309 IRB.getPtrTy(), IRB.getPtrTy(), IntptrTy);
311 M.getOrInsertFunction(
"__tsan_memcpy", Attr, IRB.getPtrTy(),
312 IRB.getPtrTy(), IRB.getPtrTy(), IntptrTy);
313 MemsetFn =
M.getOrInsertFunction(
316 IRB.getPtrTy(), IRB.getPtrTy(), IRB.getInt32Ty(), IntptrTy);
320 if (
MDNode *Tag =
I->getMetadata(LLVMContext::MD_tbaa))
321 return Tag->isTBAAVtableAccess();
334 if (GV->hasSection()) {
337 auto OF = M->getTargetTriple().getObjectFormat();
353bool ThreadSanitizer::addrPointsToConstantData(
Value *Addr) {
356 Addr =
GEP->getPointerOperand();
359 if (GV->isConstant()) {
361 NumOmittedReadsFromConstantGlobals++;
367 NumOmittedReadsFromVtable++;
386void ThreadSanitizer::chooseInstructionsToInstrument(
400 const auto WriteEntry = WriteTargets.
find(Addr);
401 if (!Opts.tsan_instrument_read_before_write &&
402 WriteEntry != WriteTargets.
end()) {
403 auto &WI =
All[WriteEntry->second];
406 const bool AnyVolatile = Opts.tsan_distinguish_volatile &&
412 WI.Flags |= InstructionInfo::kCompoundRW;
413 NumOmittedReadsBeforeWrite++;
418 if (addrPointsToConstantData(Addr)) {
427 Opts.tsan_omit_by_pointer_capturing) {
431 NumOmittedNonCaptured++;
440 WriteTargets[Addr] =
All.size() - 1;
456void ThreadSanitizer::InsertRuntimeIgnores(
Function &
F) {
458 IRB.CreateCall(TsanIgnoreBegin);
460 Opts.tsan_handle_cxx_exceptions);
463 AtExit->CreateCall(TsanIgnoreEnd);
467bool ThreadSanitizer::sanitizeFunction(
Function &
F,
476 if (
F.hasFnAttribute(Attribute::Naked))
481 if (
F.hasFnAttribute(Attribute::DisableSanitizerInstrumentation))
491 bool SanitizeFunction =
F.hasFnAttribute(Attribute::SanitizeThread);
496 for (
auto &Inst : BB) {
498 if (Inst.hasMetadata(LLVMContext::MD_nosanitize))
510 chooseInstructionsToInstrument(LocalLoadsAndStores, AllLoadsAndStores,
514 chooseInstructionsToInstrument(LocalLoadsAndStores, AllLoadsAndStores,
DL);
522 if (Opts.tsan_instrument_memory_accesses && SanitizeFunction)
523 for (
const auto &
II : AllLoadsAndStores) {
524 Res |= instrumentLoadOrStore(
II,
DL);
529 if (Opts.tsan_instrument_atomics)
530 for (
auto *Inst : AtomicAccesses) {
531 Res |= instrumentAtomic(Inst,
DL);
534 if (Opts.tsan_instrument_memintrinsics && SanitizeFunction)
535 for (
auto *Inst : MemIntrinCalls) {
536 Res |= instrumentMemIntrinsic(Inst);
539 if (
F.hasFnAttribute(
"sanitize_thread_no_checking_at_run_time")) {
540 assert(!
F.hasFnAttribute(Attribute::SanitizeThread));
542 InsertRuntimeIgnores(
F);
546 if ((Res ||
HasCalls) && Opts.tsan_instrument_func_entry_exit) {
549 DL.getProgramAddressSpace());
550 Value *ReturnAddress = IRB.CreateIntrinsic(
551 Intrinsic::returnaddress, {ProgramAsPtrTy}, IRB.getInt32(0));
552 IRB.CreateCall(TsanFuncEntry, ReturnAddress);
557 AtExit->CreateCall(TsanFuncExit, {});
564bool ThreadSanitizer::instrumentLoadOrStore(
const InstructionInfo &
II,
578 int Idx = getMemoryAccessFuncIndex(OrigTy, Addr,
DL);
588 StoredValue = IRB.CreateExtractElement(
589 StoredValue, ConstantInt::get(IRB.getInt32Ty(), 0));
591 StoredValue = IRB.CreateIntToPtr(StoredValue, IRB.getPtrTy());
593 IRB.CreateCall(TsanVptrUpdate, {Addr, StoredValue});
594 NumInstrumentedVtableWrites++;
598 IRB.CreateCall(TsanVptrLoad, Addr);
599 NumInstrumentedVtableReads++;
605 const bool IsCompoundRW = Opts.tsan_compound_read_before_write &&
606 (
II.Flags & InstructionInfo::kCompoundRW);
607 const bool IsVolatile = Opts.tsan_distinguish_volatile &&
610 assert((!IsVolatile || !IsCompoundRW) &&
"Compound volatile invalid!");
612 const uint32_t
TypeSize =
DL.getTypeStoreSizeInBits(OrigTy);
616 OnAccessFunc = TsanCompoundRW[
Idx];
618 OnAccessFunc = IsWrite ? TsanVolatileWrite[
Idx] : TsanVolatileRead[
Idx];
620 OnAccessFunc = IsWrite ? TsanWrite[
Idx] : TsanRead[
Idx];
623 OnAccessFunc = TsanUnalignedCompoundRW[
Idx];
625 OnAccessFunc = IsWrite ? TsanUnalignedVolatileWrite[
Idx]
626 : TsanUnalignedVolatileRead[
Idx];
628 OnAccessFunc = IsWrite ? TsanUnalignedWrite[
Idx] : TsanUnalignedRead[
Idx];
630 IRB.CreateCall(OnAccessFunc, Addr);
631 if (IsCompoundRW || IsWrite)
632 NumInstrumentedWrites++;
633 if (IsCompoundRW || !IsWrite)
634 NumInstrumentedReads++;
663bool ThreadSanitizer::instrumentMemIntrinsic(
Instruction *
I) {
666 Value *Cast1 = IRB.CreateIntCast(
M->getArgOperand(1), IRB.getInt32Ty(),
false);
667 Value *Cast2 = IRB.CreateIntCast(
M->getArgOperand(2), IntptrTy,
false);
670 {
M->getArgOperand(0),
673 I->eraseFromParent();
677 {
M->getArgOperand(0),
679 IRB.CreateIntCast(
M->getArgOperand(2), IntptrTy,
false)});
680 I->eraseFromParent();
696 Value *Addr = LI->getPointerOperand();
697 Type *OrigTy = LI->getType();
698 int Idx = getMemoryAccessFuncIndex(OrigTy, Addr,
DL);
703 Value *
C = IRB.CreateCall(TsanAtomicLoad[Idx], Args);
704 Value *Cast = IRB.CreateBitOrPointerCast(
C, OrigTy);
706 I->eraseFromParent();
708 Value *Addr =
SI->getPointerOperand();
710 getMemoryAccessFuncIndex(
SI->getValueOperand()->getType(), Addr,
DL);
713 const unsigned ByteSize = 1U <<
Idx;
714 const unsigned BitSize = ByteSize * 8;
717 IRB.CreateBitOrPointerCast(
SI->getValueOperand(), Ty),
719 IRB.CreateCall(TsanAtomicStore[Idx], Args);
720 SI->eraseFromParent();
722 Value *Addr = RMWI->getPointerOperand();
724 getMemoryAccessFuncIndex(RMWI->getValOperand()->getType(), Addr,
DL);
730 const unsigned ByteSize = 1U <<
Idx;
731 const unsigned BitSize = ByteSize * 8;
733 Value *Val = RMWI->getValOperand();
734 Value *
Args[] = {Addr, IRB.CreateBitOrPointerCast(Val, Ty),
736 Value *
C = IRB.CreateCall(
F, Args);
738 I->eraseFromParent();
740 Value *Addr = CASI->getPointerOperand();
741 Type *OrigOldValTy = CASI->getNewValOperand()->getType();
742 int Idx = getMemoryAccessFuncIndex(OrigOldValTy, Addr,
DL);
745 const unsigned ByteSize = 1U <<
Idx;
746 const unsigned BitSize = ByteSize * 8;
749 IRB.CreateBitOrPointerCast(CASI->getCompareOperand(), Ty);
751 IRB.CreateBitOrPointerCast(CASI->getNewValOperand(), Ty);
757 CallInst *
C = IRB.CreateCall(TsanAtomicCAS[Idx], Args);
760 if (Ty != OrigOldValTy) {
762 OldVal = IRB.CreateIntToPtr(
C, OrigOldValTy);
767 Res = IRB.CreateInsertValue(Res,
Success, 1);
770 I->eraseFromParent();
774 ? TsanAtomicSignalFence
775 : TsanAtomicThreadFence;
776 IRB.CreateCall(
F, Args);
777 FI->eraseFromParent();
782int ThreadSanitizer::getMemoryAccessFuncIndex(
Type *OrigTy,
Value *Addr,
789 uint32_t
TypeSize =
DL.getTypeStoreSizeInBits(OrigTy);
792 NumAccessesWithBadSize++;
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static const size_t kNumberOfAccessSizes
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static bool insertModuleCtor(Module &M)
This file defines the DenseMap class.
Module.h This file contains the declarations for the Module class.
uint64_t IntrinsicInst * II
FunctionAnalysisManager FAM
ModuleAnalysisManager MAM
This file defines the SmallString class.
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
static void initialize(TargetLibraryInfoImpl &TLI, const Triple &T, const llvm::StringTable &StandardNames, VectorLibrary VecLib)
Initialize the set of available library functions based on the specified target triple.
static bool shouldInstrumentReadWriteFromAddress(const Module *M, Value *Addr)
static bool isVtableAccess(Instruction *I)
static bool isTsanAtomic(const Instruction *I)
const char kTsanModuleCtorName[]
static ConstantInt * createOrdering(IRBuilder<> *IRB, AtomicOrdering ord)
const char kTsanInitName[]
an instruction to allocate memory on the stack
An instruction that atomically checks whether a specified value is in a memory location,...
an instruction that atomically reads a memory location, combines it with another value,...
This class represents a function call, abstracting a target machine's calling convention.
This is the shared class of boolean and integer constants.
A parsed version of the target data layout string in and methods for querying it.
iterator find(const_arg_type_t< KeyT > Val)
EscapeEnumerator - This is a little algorithm to find all escape points from a function so that "fina...
An instruction for ordering other memory operations.
A handy container for a FunctionType+Callee-pointer pair, which can be passed around as a single enti...
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
ConstantInt * getInt32(uint32_t C)
Get a constant 32-bit value.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Class to represent integer types.
This is an important class for using LLVM in a threaded context.
An instruction for reading from memory.
This class wraps the llvm.memset and llvm.memset.inline intrinsics.
This class wraps the llvm.memcpy/memmove intrinsics.
A Module instance is used to store all the information related to an LLVM module.
static LLVM_ABI PointerType * get(LLVMContext &C, unsigned AddressSpace)
This constructs an opaque pointer to an object in a numbered address space.
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
Represent a constant reference to a string, i.e.
Analysis pass providing the TargetLibraryInfo.
Provides information about what library functions are available for the current target.
AttributeList getAttrList(LLVMContext *C, ArrayRef< unsigned > ArgNos, bool Signed, bool Ret=false, AttributeList AL=AttributeList()) const
The instances of the Type class are immutable: once they are created, they are never changed.
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
LLVM_ABI unsigned getPointerAddressSpace() const
Get the address space of this pointer or pointer vector type.
bool isSized() const
Return true if it makes sense to take the size of this type.
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
LLVM_ABI bool isScalableTy() const
Return true if this is a type whose size is a known multiple of vscale.
bool isIntegerTy() const
True if this is an instance of IntegerType.
static LLVM_ABI IntegerType * getIntNTy(LLVMContext &C, unsigned N)
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
LLVM_ABI const Value * stripInBoundsOffsets(function_ref< void(const Value *)> Func=[](const Value *) {}) const
Strip off pointer casts and inbounds GEPs.
LLVM_ABI bool isSwiftError() const
Return true if this value is a swifterror value.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char IsVolatile[]
Key for Kernel::Arg::Metadata::mIsVolatile.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
@ SingleThread
Synchronized with respect to signal handlers executing in the same thread.
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI AllocaInst * findAllocaForValue(Value *V, bool OffsetZero=false)
Returns unique alloca where the value comes from, or nullptr.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
std::string utostr(uint64_t X, bool isNeg=false)
LLVM_ABI std::string getInstrProfSectionName(InstrProfSectKind IPSK, Triple::ObjectFormatType OF, bool AddSegmentInfo=true)
Return the name of the profile section corresponding to IPSK.
int countr_zero(T Val)
Count number of 0's from the least significant bit to the most stopping at the first 1.
auto reverse(ContainerTy &&C)
LLVM_ABI std::pair< Function *, FunctionCallee > getOrCreateSanitizerCtorAndInitFunctions(Module &M, StringRef CtorName, StringRef InitName, ArrayRef< Type * > InitArgTypes, ArrayRef< Value * > InitArgs, function_ref< void(Function *, FunctionCallee)> FunctionsCreatedCallback, StringRef VersionCheckName=StringRef(), bool Weak=false)
Creates sanitizer constructor function lazily.
std::optional< SyncScope::ID > getAtomicSyncScopeID(const Instruction *I)
A helper function that returns an atomic operation's sync scope; returns std::nullopt if it is not an...
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
@ Success
The lock was released successfully.
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
AtomicOrdering
Atomic ordering for LLVM's memory model.
DWARFExpression::Operation Op
LLVM_ABI bool PointerMayBeCaptured(const Value *V, bool ReturnCaptures, unsigned MaxUsesToExplore=0)
PointerMayBeCaptured - Return true if this pointer value may be captured by the enclosing function (w...
LLVM_ABI 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.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Type * getLoadStoreType(const Value *I)
A helper function that returns the type of a load or store instruction.
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
LLVM_ABI 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...
LLVM_ABI bool checkIfAlreadyInstrumented(Module &M, StringRef Flag)
Check if module has flag attached, if not add the flag.
std::string itostr(int64_t X)
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
This struct is a compact representation of a valid (non-zero power of two) alignment.
static void ensureDebugInfo(IRBuilder<> &IRB, const Function &F)
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM)