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(InstrumentationOptions::Global);
173 IntptrTy =
DL.getIntPtrType(Ctx);
177 Attr = Attr.addFnAttribute(Ctx, Attribute::NoUnwind);
179 TsanFuncEntry = M.getOrInsertFunction(
"__tsan_func_entry", Attr,
180 IRB.getVoidTy(), IRB.getPtrTy());
182 M.getOrInsertFunction(
"__tsan_func_exit", Attr, IRB.getVoidTy());
183 TsanIgnoreBegin = M.getOrInsertFunction(
"__tsan_ignore_thread_begin", Attr,
186 M.getOrInsertFunction(
"__tsan_ignore_thread_end", Attr, IRB.getVoidTy());
189 const unsigned ByteSize = 1U << i;
190 const unsigned BitSize = ByteSize * 8;
191 std::string ByteSizeStr =
utostr(ByteSize);
192 std::string BitSizeStr =
utostr(BitSize);
194 TsanRead[i] = M.getOrInsertFunction(ReadName, Attr, IRB.getVoidTy(),
198 TsanWrite[i] = M.getOrInsertFunction(WriteName, Attr, IRB.getVoidTy(),
201 SmallString<64> UnalignedReadName(
"__tsan_unaligned_read" + ByteSizeStr);
202 TsanUnalignedRead[i] = M.getOrInsertFunction(
203 UnalignedReadName, Attr, IRB.getVoidTy(), IRB.getPtrTy());
205 SmallString<64> UnalignedWriteName(
"__tsan_unaligned_write" + ByteSizeStr);
206 TsanUnalignedWrite[i] = M.getOrInsertFunction(
207 UnalignedWriteName, Attr, IRB.getVoidTy(), IRB.getPtrTy());
209 SmallString<64> VolatileReadName(
"__tsan_volatile_read" + ByteSizeStr);
210 TsanVolatileRead[i] = M.getOrInsertFunction(
211 VolatileReadName, Attr, IRB.getVoidTy(), IRB.getPtrTy());
213 SmallString<64> VolatileWriteName(
"__tsan_volatile_write" + ByteSizeStr);
214 TsanVolatileWrite[i] = M.getOrInsertFunction(
215 VolatileWriteName, Attr, IRB.getVoidTy(), IRB.getPtrTy());
217 SmallString<64> UnalignedVolatileReadName(
"__tsan_unaligned_volatile_read" +
219 TsanUnalignedVolatileRead[i] = M.getOrInsertFunction(
220 UnalignedVolatileReadName, Attr, IRB.getVoidTy(), IRB.getPtrTy());
223 "__tsan_unaligned_volatile_write" + ByteSizeStr);
224 TsanUnalignedVolatileWrite[i] = M.getOrInsertFunction(
225 UnalignedVolatileWriteName, Attr, IRB.getVoidTy(), IRB.getPtrTy());
228 TsanCompoundRW[i] = M.getOrInsertFunction(
229 CompoundRWName, Attr, IRB.getVoidTy(), IRB.getPtrTy());
231 SmallString<64> UnalignedCompoundRWName(
"__tsan_unaligned_read_write" +
233 TsanUnalignedCompoundRW[i] = M.getOrInsertFunction(
234 UnalignedCompoundRWName, Attr, IRB.getVoidTy(), IRB.getPtrTy());
238 SmallString<32> AtomicLoadName(
"__tsan_atomic" + BitSizeStr +
"_load");
240 M.getOrInsertFunction(AtomicLoadName,
242 BitSize <= 32, Attr),
246 using Idxs = std::vector<unsigned>;
247 Idxs Idxs2Or12 ((BitSize <= 32) ? Idxs({1, 2}) : Idxs({2}));
248 Idxs Idxs34Or1234((BitSize <= 32) ? Idxs({1, 2, 3, 4}) : Idxs({3, 4}));
249 SmallString<32> AtomicStoreName(
"__tsan_atomic" + BitSizeStr +
"_store");
250 TsanAtomicStore[i] =
M.getOrInsertFunction(
252 TLI.
getAttrList(&Ctx, Idxs2Or12,
true,
false, Attr),
253 IRB.getVoidTy(), PtrTy, Ty, OrdTy);
257 TsanAtomicRMW[
Op][i] =
nullptr;
258 const char *NamePart =
nullptr;
260 NamePart =
"_exchange";
262 NamePart =
"_fetch_add";
264 NamePart =
"_fetch_sub";
266 NamePart =
"_fetch_and";
268 NamePart =
"_fetch_or";
270 NamePart =
"_fetch_xor";
272 NamePart =
"_fetch_nand";
276 TsanAtomicRMW[
Op][i] =
M.getOrInsertFunction(
279 BitSize <= 32, Attr),
280 Ty, PtrTy, Ty, OrdTy);
284 "_compare_exchange_val");
285 TsanAtomicCAS[i] =
M.getOrInsertFunction(
288 BitSize <= 32, Attr),
289 Ty, PtrTy, Ty, Ty, OrdTy, OrdTy);
292 M.getOrInsertFunction(
"__tsan_vptr_update", Attr, IRB.getVoidTy(),
293 IRB.getPtrTy(), IRB.getPtrTy());
294 TsanVptrLoad =
M.getOrInsertFunction(
"__tsan_vptr_read", Attr,
295 IRB.getVoidTy(), IRB.getPtrTy());
296 TsanAtomicThreadFence =
M.getOrInsertFunction(
297 "__tsan_atomic_thread_fence",
299 IRB.getVoidTy(), OrdTy);
301 TsanAtomicSignalFence =
M.getOrInsertFunction(
302 "__tsan_atomic_signal_fence",
304 IRB.getVoidTy(), OrdTy);
307 M.getOrInsertFunction(
"__tsan_memmove", Attr, IRB.getPtrTy(),
308 IRB.getPtrTy(), IRB.getPtrTy(), IntptrTy);
310 M.getOrInsertFunction(
"__tsan_memcpy", Attr, IRB.getPtrTy(),
311 IRB.getPtrTy(), IRB.getPtrTy(), IntptrTy);
312 MemsetFn =
M.getOrInsertFunction(
315 IRB.getPtrTy(), IRB.getPtrTy(), IRB.getInt32Ty(), IntptrTy);
319 if (
MDNode *Tag =
I->getMetadata(LLVMContext::MD_tbaa))
320 return Tag->isTBAAVtableAccess();
333 if (GV->hasSection()) {
336 auto OF = M->getTargetTriple().getObjectFormat();
352bool ThreadSanitizer::addrPointsToConstantData(
Value *Addr) {
355 Addr =
GEP->getPointerOperand();
358 if (GV->isConstant()) {
360 NumOmittedReadsFromConstantGlobals++;
366 NumOmittedReadsFromVtable++;
385void ThreadSanitizer::chooseInstructionsToInstrument(
399 const auto WriteEntry = WriteTargets.
find(Addr);
400 if (!Opts.tsan_instrument_read_before_write &&
401 WriteEntry != WriteTargets.
end()) {
402 auto &WI =
All[WriteEntry->second];
405 const bool AnyVolatile = Opts.tsan_distinguish_volatile &&
411 WI.Flags |= InstructionInfo::kCompoundRW;
412 NumOmittedReadsBeforeWrite++;
417 if (addrPointsToConstantData(Addr)) {
426 Opts.tsan_omit_by_pointer_capturing) {
430 NumOmittedNonCaptured++;
439 WriteTargets[Addr] =
All.size() - 1;
455void ThreadSanitizer::InsertRuntimeIgnores(
Function &
F) {
457 IRB.CreateCall(TsanIgnoreBegin);
459 Opts.tsan_handle_cxx_exceptions);
462 AtExit->CreateCall(TsanIgnoreEnd);
466bool ThreadSanitizer::sanitizeFunction(
Function &
F,
475 if (
F.hasFnAttribute(Attribute::Naked))
480 if (
F.hasFnAttribute(Attribute::DisableSanitizerInstrumentation))
490 bool SanitizeFunction =
F.hasFnAttribute(Attribute::SanitizeThread);
495 for (
auto &Inst : BB) {
497 if (Inst.hasMetadata(LLVMContext::MD_nosanitize))
509 chooseInstructionsToInstrument(LocalLoadsAndStores, AllLoadsAndStores,
513 chooseInstructionsToInstrument(LocalLoadsAndStores, AllLoadsAndStores,
DL);
521 if (Opts.tsan_instrument_memory_accesses && SanitizeFunction)
522 for (
const auto &
II : AllLoadsAndStores) {
523 Res |= instrumentLoadOrStore(
II,
DL);
528 if (Opts.tsan_instrument_atomics)
529 for (
auto *Inst : AtomicAccesses) {
530 Res |= instrumentAtomic(Inst,
DL);
533 if (Opts.tsan_instrument_memintrinsics && SanitizeFunction)
534 for (
auto *Inst : MemIntrinCalls) {
535 Res |= instrumentMemIntrinsic(Inst);
538 if (
F.hasFnAttribute(
"sanitize_thread_no_checking_at_run_time")) {
539 assert(!
F.hasFnAttribute(Attribute::SanitizeThread));
541 InsertRuntimeIgnores(
F);
545 if ((Res ||
HasCalls) && Opts.tsan_instrument_func_entry_exit) {
548 DL.getProgramAddressSpace());
549 Value *ReturnAddress = IRB.CreateIntrinsic(
550 Intrinsic::returnaddress, {ProgramAsPtrTy}, IRB.getInt32(0));
551 IRB.CreateCall(TsanFuncEntry, ReturnAddress);
556 AtExit->CreateCall(TsanFuncExit, {});
563bool ThreadSanitizer::instrumentLoadOrStore(
const InstructionInfo &
II,
577 int Idx = getMemoryAccessFuncIndex(OrigTy, Addr,
DL);
587 StoredValue = IRB.CreateExtractElement(
588 StoredValue, ConstantInt::get(IRB.getInt32Ty(), 0));
590 StoredValue = IRB.CreateIntToPtr(StoredValue, IRB.getPtrTy());
592 IRB.CreateCall(TsanVptrUpdate, {Addr, StoredValue});
593 NumInstrumentedVtableWrites++;
597 IRB.CreateCall(TsanVptrLoad, Addr);
598 NumInstrumentedVtableReads++;
604 const bool IsCompoundRW = Opts.tsan_compound_read_before_write &&
605 (
II.Flags & InstructionInfo::kCompoundRW);
606 const bool IsVolatile = Opts.tsan_distinguish_volatile &&
609 assert((!IsVolatile || !IsCompoundRW) &&
"Compound volatile invalid!");
611 const uint32_t
TypeSize =
DL.getTypeStoreSizeInBits(OrigTy);
615 OnAccessFunc = TsanCompoundRW[
Idx];
617 OnAccessFunc = IsWrite ? TsanVolatileWrite[
Idx] : TsanVolatileRead[
Idx];
619 OnAccessFunc = IsWrite ? TsanWrite[
Idx] : TsanRead[
Idx];
622 OnAccessFunc = TsanUnalignedCompoundRW[
Idx];
624 OnAccessFunc = IsWrite ? TsanUnalignedVolatileWrite[
Idx]
625 : TsanUnalignedVolatileRead[
Idx];
627 OnAccessFunc = IsWrite ? TsanUnalignedWrite[
Idx] : TsanUnalignedRead[
Idx];
629 IRB.CreateCall(OnAccessFunc, Addr);
630 if (IsCompoundRW || IsWrite)
631 NumInstrumentedWrites++;
632 if (IsCompoundRW || !IsWrite)
633 NumInstrumentedReads++;
662bool ThreadSanitizer::instrumentMemIntrinsic(
Instruction *
I) {
665 Value *Cast1 = IRB.CreateIntCast(
M->getArgOperand(1), IRB.getInt32Ty(),
false);
666 Value *Cast2 = IRB.CreateIntCast(
M->getArgOperand(2), IntptrTy,
false);
669 {
M->getArgOperand(0),
672 I->eraseFromParent();
676 {
M->getArgOperand(0),
678 IRB.CreateIntCast(
M->getArgOperand(2), IntptrTy,
false)});
679 I->eraseFromParent();
695 Value *Addr = LI->getPointerOperand();
696 Type *OrigTy = LI->getType();
697 int Idx = getMemoryAccessFuncIndex(OrigTy, Addr,
DL);
702 Value *
C = IRB.CreateCall(TsanAtomicLoad[Idx], Args);
703 Value *Cast = IRB.CreateBitOrPointerCast(
C, OrigTy);
705 I->eraseFromParent();
707 Value *Addr =
SI->getPointerOperand();
709 getMemoryAccessFuncIndex(
SI->getValueOperand()->getType(), Addr,
DL);
712 const unsigned ByteSize = 1U <<
Idx;
713 const unsigned BitSize = ByteSize * 8;
716 IRB.CreateBitOrPointerCast(
SI->getValueOperand(), Ty),
718 IRB.CreateCall(TsanAtomicStore[Idx], Args);
719 SI->eraseFromParent();
721 Value *Addr = RMWI->getPointerOperand();
723 getMemoryAccessFuncIndex(RMWI->getValOperand()->getType(), Addr,
DL);
729 const unsigned ByteSize = 1U <<
Idx;
730 const unsigned BitSize = ByteSize * 8;
732 Value *Val = RMWI->getValOperand();
733 Value *
Args[] = {Addr, IRB.CreateBitOrPointerCast(Val, Ty),
735 Value *
C = IRB.CreateCall(
F, Args);
737 I->eraseFromParent();
739 Value *Addr = CASI->getPointerOperand();
740 Type *OrigOldValTy = CASI->getNewValOperand()->getType();
741 int Idx = getMemoryAccessFuncIndex(OrigOldValTy, Addr,
DL);
744 const unsigned ByteSize = 1U <<
Idx;
745 const unsigned BitSize = ByteSize * 8;
748 IRB.CreateBitOrPointerCast(CASI->getCompareOperand(), Ty);
750 IRB.CreateBitOrPointerCast(CASI->getNewValOperand(), Ty);
756 CallInst *
C = IRB.CreateCall(TsanAtomicCAS[Idx], Args);
759 if (Ty != OrigOldValTy) {
761 OldVal = IRB.CreateIntToPtr(
C, OrigOldValTy);
766 Res = IRB.CreateInsertValue(Res,
Success, 1);
769 I->eraseFromParent();
773 ? TsanAtomicSignalFence
774 : TsanAtomicThreadFence;
775 IRB.CreateCall(
F, Args);
776 FI->eraseFromParent();
781int ThreadSanitizer::getMemoryAccessFuncIndex(
Type *OrigTy,
Value *Addr,
788 uint32_t
TypeSize =
DL.getTypeStoreSizeInBits(OrigTy);
791 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)