44#define DEBUG_TYPE "csan"
47 "csan-instrument-memory-accesses",
cl::init(
true),
51 cl::desc(
"Instrument function entry and exit"),
54 "csan-handle-cxx-exceptions",
cl::init(
true),
55 cl::desc(
"Handle C++ exceptions (insert cleanup blocks for unwinding)"),
62 "csan-instrument-memintrinsics",
cl::init(
true),
65 "csan-distinguish-volatile",
cl::init(
false),
66 cl::desc(
"Treat aligned volatile accesses up to 8 bytes as atomic"),
68STATISTIC(NumInstrumentedReads,
"Number of instrumented reads");
69STATISTIC(NumInstrumentedWrites,
"Number of instrumented writes");
71 "Number of reads ignored due to following writes");
79 "__csan_read1",
"__csan_read2",
"__csan_read4",
"__csan_read8",
82 "__csan_write1",
"__csan_write2",
"__csan_write4",
"__csan_write8",
85 "__csan_unaligned_read1",
"__csan_unaligned_read2",
86 "__csan_unaligned_read4",
"__csan_unaligned_read8",
87 "__csan_unaligned_read16"};
89 "__csan_unaligned_write1",
"__csan_unaligned_write2",
90 "__csan_unaligned_write4",
"__csan_unaligned_write8",
91 "__csan_unaligned_write16"};
93 "__csan_read_write1",
"__csan_read_write2",
"__csan_read_write4",
94 "__csan_read_write8",
"__csan_read_write16"};
96 {
"__csan_unaligned_read_write1",
"__csan_unaligned_read_write2",
97 "__csan_unaligned_read_write4",
"__csan_unaligned_read_write8",
98 "__csan_unaligned_read_write16"};
103enum class AccessFlags :
unsigned {
129 if (Ty->isScalableTy())
136 return static_cast<int>(
Idx);
146 WriteTargets[Addr] =
Store;
157 if (LaterWrite && !AnyVolatile) {
158 ++NumOmittedReadsBeforeWrite;
167static bool addressSpaceMayRace(
const Triple &
T,
unsigned AS) {
186struct ConcurrencySanitizer {
187 bool sanitizeFunction(
Function &
F,
const TargetLibraryInfo &TLI);
190 struct MemoryAccessLists {
191 SmallVector<Instruction *, 8> LoadsAndStores;
192 SmallVector<Instruction *, 8> AtomicAccesses;
194 bool HasCalls =
false;
198 void collectMemoryAccesses(
Function &
F, MemoryAccessLists &Out);
199 bool instrumentLoadOrStore(Instruction *
I,
const DataLayout &
DL);
200 bool instrumentAtomic(Instruction *
I,
const DataLayout &
DL);
201 bool instrumentMemIntrinsic(IntrinsicInst *
II,
const DataLayout &
DL);
202 bool insertAccessProbe(Instruction *
I,
Value *Addr,
Type *AccessTy,
203 const DataLayout &
DL,
bool IsWrite,
bool IsCompound,
205 bool shouldInstrumentAddress(
Value *Addr)
const;
206 bool shouldInstrumentAccess(Instruction *
I)
const;
214 Type *IntptrTy =
nullptr;
215 IntegerType *FlagsTy =
nullptr;
230 FunctionCallee CsanFuncEntry;
232 FunctionCallee CsanFuncExit;
234 FunctionCallee CsanIgnoreBegin;
236 FunctionCallee CsanIgnoreEnd;
238 FunctionCallee CsanReadRange;
240 FunctionCallee CsanWriteRange;
242 FunctionCallee CsanAtomicThreadFence;
244 FunctionCallee CsanAtomicSignalFence;
258 ConcurrencySanitizer CSan;
275 IntptrTy = M.getDataLayout().getIntPtrType(Ctx);
283 M.getOrInsertFunction(
"__csan_func_entry", Attr, VoidTy, PtrTy);
284 CsanFuncExit = M.getOrInsertFunction(
"__csan_func_exit", Attr, VoidTy);
286 M.getOrInsertFunction(
"__csan_ignore_thread_begin", Attr, VoidTy);
288 M.getOrInsertFunction(
"__csan_ignore_thread_end", Attr, VoidTy);
290 return M.getOrInsertFunction(Name, Attr, VoidTy, PtrTy, FlagsTy);
301 CsanReadRange =
M.getOrInsertFunction(
"__csan_read_range", Attr, VoidTy,
302 PtrTy, IntptrTy, FlagsTy);
303 CsanWriteRange =
M.getOrInsertFunction(
"__csan_write_range", Attr, VoidTy,
304 PtrTy, IntptrTy, FlagsTy);
305 CsanAtomicThreadFence =
M.getOrInsertFunction(
306 "__csan_atomic_thread_fence",
307 TLI.
getAttrList(&Ctx, {0},
true,
false, Attr), VoidTy,
309 CsanAtomicSignalFence =
M.getOrInsertFunction(
310 "__csan_atomic_signal_fence",
311 TLI.
getAttrList(&Ctx, {0},
true,
false, Attr), VoidTy,
315bool ConcurrencySanitizer::sanitizeFunction(
Function &
F,
324 if (
F.hasFnAttribute(Attribute::Naked))
329 if (
F.hasFnAttribute(Attribute::DisableSanitizerInstrumentation))
333 MemoryAccessLists Acc;
334 collectMemoryAccesses(
F, Acc);
336 const bool SuppressChecking =
337 F.hasFnAttribute(
"sanitize_concurrency_no_checking_at_run_time");
338 const bool SanitizeFunction =
339 F.hasFnAttribute(Attribute::SanitizeConcurrency) && !SuppressChecking;
340 const bool MayInstrument =
345 const bool NeedsRuntimeIgnores = SuppressChecking && Acc.HasCalls;
347 if (!MayInstrument && !NeedsRuntimeIgnores && !NeedsFuncEntryExit)
356 Res |= instrumentLoadOrStore(
I,
DL);
360 Res |= instrumentAtomic(
I,
DL);
364 Res |= instrumentMemIntrinsic(
II,
DL);
366 if (NeedsRuntimeIgnores) {
367 insertRuntimeIgnores(
F);
372 insertFuncEntryExit(
F);
378bool ConcurrencySanitizer::shouldInstrumentAddress(
Value *Addr)
const {
381 if (GV->hasSection()) {
392 if (
Mod->getDataLayout().getPointerSizeInBits(AS) > 64)
394 return addressSpaceMayRace(
Mod->getTargetTriple(), AS);
397bool ConcurrencySanitizer::shouldInstrumentAccess(
Instruction *
I)
const {
400 if (!shouldInstrumentAddress(Addr))
405 if (GV->isConstant())
416void ConcurrencySanitizer::collectMemoryAccesses(
Function &
F,
417 MemoryAccessLists &Out) {
423 if (Inst.hasMetadata(LLVMContext::MD_nosanitize))
425 if (isAtomicMemoryAccess(&Inst))
426 Out.AtomicAccesses.push_back(&Inst);
428 shouldInstrumentAccess(&Inst))
434 selectMemoryAccesses(LocalLoadsAndStores,
Out.LoadsAndStores);
437 selectMemoryAccesses(LocalLoadsAndStores,
Out.LoadsAndStores);
441bool ConcurrencySanitizer::instrumentLoadOrStore(
Instruction *
I,
449 ++NumInstrumentedWrites;
451 ++NumInstrumentedReads;
455bool ConcurrencySanitizer::instrumentAtomic(
Instruction *
I,
460 ? CsanAtomicSignalFence
461 : CsanAtomicThreadFence;
466 Value *Addr =
nullptr;
467 Type *AccessTy =
nullptr;
469 bool IsCompound =
false;
471 Addr = LI->getPointerOperand();
472 AccessTy = LI->getType();
475 Addr =
SI->getPointerOperand();
476 AccessTy =
SI->getValueOperand()->getType();
478 Addr = RMW->getPointerOperand();
479 AccessTy = RMW->getValOperand()->getType();
483 Addr = CAS->getPointerOperand();
484 AccessTy = CAS->getNewValOperand()->getType();
490 if (!shouldInstrumentAddress(Addr))
492 if (!insertAccessProbe(
I, Addr, AccessTy,
DL, IsWrite, IsCompound,
495 if (IsCompound || IsWrite)
496 ++NumInstrumentedWrites;
497 if (IsCompound || !IsWrite)
498 ++NumInstrumentedReads;
506 Value *Dst =
MI ?
MI->getRawDest() : MSP->getRawDest();
507 Value *Src =
nullptr;
509 Src = MT->getRawSource();
511 bool InstrumentRead = Src && shouldInstrumentAddress(Src);
512 bool InstrumentWrite = shouldInstrumentAddress(Dst);
513 if (!InstrumentRead && !InstrumentWrite)
525 getFlags(
MI &&
MI->isAtomic() ? AccessFlags::Atomic : AccessFlags::None);
526 if (InstrumentRead) {
528 ++NumInstrumentedReads;
530 if (InstrumentWrite) {
532 ++NumInstrumentedWrites;
540 bool IsCompound,
bool IsAtomic) {
543 AccessFlags
Flags = AccessFlags::None;
545 Flags |= AccessFlags::Atomic;
547 Flags |= AccessFlags::Compound;
548 int Idx = getAccessSizeIndex(AccessTy,
DL);
554 IRB.
CreateCall(IsWrite ? CsanWriteRange : CsanReadRange,
555 {getCallbackAddress(IRB, Addr),
Len,
getFlags(Flags)});
575 uint32_t
TypeSize =
DL.getTypeStoreSizeInBits(AccessTy);
582 Callback = IsWrite ? CsanUnalignedWrite[
Idx] : CsanUnalignedRead[
Idx];
587 Value *CallbackAddr = getCallbackAddress(IRB, Addr);
596 IsAligned,
getFlags(Flags | AccessFlags::Atomic), FlagsVal);
598 IRB.
CreateCall(Callback, {CallbackAddr, FlagsVal});
602void ConcurrencySanitizer::insertFuncEntryExit(
Function &
F) {
605 Type *ProgramAsPtrTy =
614 AtExit->CreateCall(CsanFuncExit);
618void ConcurrencySanitizer::insertRuntimeIgnores(
Function &
F) {
624 AtExit->CreateCall(CsanIgnoreEnd);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU address space definition.
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Atomic ordering constants.
static cl::opt< bool > ClInstrumentAtomics("csan-instrument-atomics", cl::init(true), cl::desc("Instrument atomics"), cl::Hidden)
static constexpr StringLiteral kCsanUnalignedReadNames[kNumAccessSizes]
static cl::opt< bool > ClInstrumentMemoryAccesses("csan-instrument-memory-accesses", cl::init(true), cl::desc("Instrument memory accesses"), cl::Hidden)
static constexpr StringLiteral kCsanWriteNames[kNumAccessSizes]
static constexpr StringLiteral kCsanReadNames[kNumAccessSizes]
static cl::opt< bool > ClDistinguishVolatile("csan-distinguish-volatile", cl::init(false), cl::desc("Treat aligned volatile accesses up to 8 bytes as atomic"), cl::Hidden)
static constexpr size_t kNumAccessSizes
static cl::opt< bool > ClInstrumentMemIntrinsics("csan-instrument-memintrinsics", cl::init(true), cl::desc("Instrument memintrinsics (memset/memcpy/memmove)"), cl::Hidden)
static constexpr StringLiteral kCsanUnalignedCompoundRWNames[kNumAccessSizes]
static cl::opt< bool > ClHandleCxxExceptions("csan-handle-cxx-exceptions", cl::init(true), cl::desc("Handle C++ exceptions (insert cleanup blocks for unwinding)"), cl::Hidden)
static constexpr StringLiteral kCsanCompoundRWNames[kNumAccessSizes]
static constexpr StringLiteral kCsanUnalignedWriteNames[kNumAccessSizes]
static cl::opt< bool > ClInstrumentFuncEntryExit("csan-instrument-func-entry-exit", cl::init(true), cl::desc("Instrument function entry and exit"), cl::Hidden)
static constexpr char kCsanInitName[]
static constexpr char kCsanModuleCtorName[]
static bool insertModuleCtor(Module &M)
This file defines the DenseMap class.
Module.h This file contains the declarations for the Module class.
NVPTX address space definition.
uint64_t IntrinsicInst * II
FunctionAnalysisManager FAM
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 uint32_t getFlags(const Symbol *Sym)
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 ConstantInt * createOrdering(IRBuilder<> *IRB, AtomicOrdering ord)
This file implements the C++20 <bit> header.
an instruction to allocate memory on the stack
unsigned getAddressSpace() const
Return the address space for the allocation.
LLVM Basic Block Representation.
This is the shared class of boolean and integer constants.
This is an important base class in LLVM.
A parsed version of the target data layout string in and methods for querying it.
ValueT lookup(const_arg_type_t< KeyT > Val) const
Return the entry for the specified key, or a default constructed value if no such entry exists.
EscapeEnumerator - This is a little algorithm to find all escape points from a function so that "fina...
A handy container for a FunctionType+Callee-pointer pair, which can be passed around as a single enti...
Common base class shared among various IRBuilders.
Value * CreateAddrSpaceCast(Value *V, Type *DestTy, const Twine &Name="", bool IsNonNull=false)
ConstantInt * getTrue()
Get the constant value for i1 true.
LLVM_ABI Value * CreateSelect(Value *C, Value *True, Value *False, const Twine &Name="", Instruction *MDFrom=nullptr)
IntegerType * getInt32Ty()
Fetch the type representing a 32-bit integer.
ConstantInt * getInt32(uint32_t C)
Get a constant 32-bit value.
Value * CreateAnd(Value *LHS, Value *RHS, const Twine &Name="")
LLVM_ABI Value * CreateIntrinsic(Intrinsic::ID ID, ArrayRef< Type * > OverloadTypes, ArrayRef< Value * > Args, FMFSource FMFSource={}, const Twine &Name="", ArrayRef< OperandBundleDef > OpBundles={}, function_ref< void(CallInst *)> SetFn=[](CallInst *) {})
Variant to create a possibly constant-folded intrinsic.
Value * CreatePtrToInt(Value *V, Type *DestTy, const Twine &Name="")
CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args={}, const Twine &Name="", MDNode *FPMathTag=nullptr)
PointerType * getPtrTy(unsigned AddrSpace=0)
Fetch the type representing a pointer.
LLVM_ABI Value * CreateTypeSize(Type *Ty, TypeSize Size)
Create an expression which evaluates to the number of units in Size at runtime.
Value * CreateIntCast(Value *V, Type *DestTy, bool isSigned, const Twine &Name="")
Value * CreateIsNull(Value *Arg, const Twine &Name="")
Return a boolean value testing if Arg == 0.
Type * getVoidTy()
Fetch the type representing void.
Value * CreateMul(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
LLVM_ABI const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
Class to represent integer types.
A wrapper class for inspecting calls to intrinsic functions.
This is an important class for using LLVM in a threaded context.
A Module instance is used to store all the information related to an LLVM module.
const Triple & getTargetTriple() const
Get the target triple which is a string describing the target host.
static LLVM_ABI PointerType * get(LLVMContext &C, unsigned AddressSpace)
This constructs an opaque pointer to an object in a numbered address space.
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.
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.
bool isVolatile() const
Return true if this is a store to a volatile memory location.
A wrapper around a string literal that serves as a proxy for constructing global tables of StringRefs...
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
Triple - Helper class for working with autoconf configuration names.
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.
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this 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.
@ LOCAL_ADDRESS
Address space for local memory.
@ FLAT_ADDRESS
Address space for flat memory.
@ GLOBAL_ADDRESS
Address space for global memory (RAT0, VTX0).
constexpr char IsVolatile[]
Key for Kernel::Arg::Metadata::mIsVolatile.
@ ADDRESS_SPACE_SHARED_CLUSTER
@ SingleThread
Synchronized with respect to signal handlers executing in the same thread.
initializer< Ty > init(const Ty &Val)
llvm::unique_function< void(llvm::Expected< T >)> Callback
A Callback<T> is a void function that accepts Expected<T>.
This is an optimization pass for GlobalISel generic memory operations.
@ LLVM_MARK_AS_BITMASK_ENUM
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.
const Value * getLoadStorePointerOperand(const Value *V)
A helper function that returns the pointer operand of a load or store instruction.
@ Store
The extracted value is stored (ExtractElement only).
LLVM_ABI std::string getInstrProfSectionName(InstrProfSectKind IPSK, Triple::ObjectFormatType OF, bool AddSegmentInfo=true)
Return the name of the profile section corresponding to IPSK.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
int countr_zero(T Val)
Count number of 0's from the least significant bit to the most stopping at the first 1.
AtomicOrderingCABI toCABI(AtomicOrdering AO)
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...
constexpr std::underlying_type_t< Enum > to_underlying(Enum E)
Returns underlying integer value of an enum.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
LLVM_ABI const Value * getUnderlyingObject(const Value *V, unsigned MaxLookup=MaxLookupSearchDepth, bool MustPreserveProvenance=false)
This method strips off any GEP address adjustments, pointer casts or llvm.threadlocal....
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...
AtomicOrdering
Atomic ordering for LLVM's memory model.
@ Mod
The access may modify the value stored in memory.
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 bool checkIfAlreadyInstrumented(Module &M, StringRef Flag)
Check if module has flag attached, if not add the flag.
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.
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM)
static void ensureDebugInfo(IRBuilder<> &IRB, const Function &F)
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)