54#define DEBUG_TYPE "sanmd"
61constexpr uint32_t kVersionPtrSizeRel = (1u << 16);
62constexpr int kCtorDtorPriority = 2;
71 static const MetadataInfo Covered;
72 static const MetadataInfo Atomics;
76 explicit constexpr MetadataInfo(
StringRef FunctionPrefix,
78 : FunctionPrefix(FunctionPrefix), SectionSuffix(SectionSuffix) {}
80const MetadataInfo MetadataInfo::Covered{
82const MetadataInfo MetadataInfo::Atomics{
93 "sanitizer-metadata-weak-callbacks",
94 cl::desc(
"Declare callbacks extern weak, and only call if non-null."),
98 cl::desc(
"Emit PCs for covered functions."),
101 cl::desc(
"Emit PCs for atomic operations."),
104 cl::desc(
"Emit PCs for start of functions that are "
105 "subject for use-after-return checking"),
110STATISTIC(NumMetadataCovered,
"Metadata attached to covered functions");
111STATISTIC(NumMetadataAtomics,
"Metadata attached to atomics");
112STATISTIC(NumMetadataUAR,
"Metadata attached to UAR functions");
120 Opts.Atomics |= ClEmitAtomics;
121 Opts.UAR |= ClEmitUAR;
122 return std::move(Opts);
125class SanitizerBinaryMetadata {
128 std::unique_ptr<SpecialCaseList> Ignorelist)
129 :
Mod(M),
Options(transformOptionsFromCl(std::move(Opts))),
130 Ignorelist(std::move(Ignorelist)), TargetTriple(M.getTargetTriple()),
131 IRB(M.getContext()) {
133 assert(TargetTriple.isOSBinFormatELF() &&
"ELF only");
134 assert(!(TargetTriple.isNVPTX() || TargetTriple.isAMDGPU()) &&
135 "Device targets are not supported");
145 Version |= kVersionPtrSizeRel;
149 void runOn(
Function &
F, MetadataInfoSet &MIS);
174 bool pretendAtomicAccess(
const Value *
Addr);
178 std::unique_ptr<SpecialCaseList> Ignorelist;
179 const Triple TargetTriple;
185bool SanitizerBinaryMetadata::run() {
199 auto *Int8PtrTy = IRB.getInt8PtrTy();
200 auto *Int8PtrPtrTy = PointerType::getUnqual(Int8PtrTy);
202 const std::array<Type *, 3> InitTypes = {
Int32Ty, Int8PtrPtrTy, Int8PtrPtrTy};
205 for (
const MetadataInfo *
MI : MIS) {
206 const std::array<
Value *, InitTypes.size()> InitArgs = {
208 getSectionMarker(getSectionStart(
MI->SectionSuffix), Int8PtrTy),
209 getSectionMarker(getSectionEnd(
MI->SectionSuffix), Int8PtrTy),
217 Mod, (
MI->FunctionPrefix +
".module_ctor").str(),
218 (
MI->FunctionPrefix +
"_add").str(), InitTypes, InitArgs,
223 Mod, (
MI->FunctionPrefix +
".module_dtor").str(),
224 (
MI->FunctionPrefix +
"_del").str(), InitTypes, InitArgs,
229 if (TargetTriple.supportsCOMDAT()) {
239 CtorComdatKey = Ctor;
240 DtorComdatKey = Dtor;
249void SanitizerBinaryMetadata::runOn(
Function &
F, MetadataInfoSet &MIS) {
252 if (
F.hasFnAttribute(Attribute::DisableSanitizerInstrumentation))
254 if (Ignorelist && Ignorelist->inSection(
"metadata",
"fun",
F.getName()))
266 bool RequiresCovered =
false;
271 RequiresCovered |= runOn(
I, MIS, MDB, FeatureMask);
275 FeatureMask &= ~kSanitizerBinaryMetadataUAR;
277 RequiresCovered =
true;
284 if (
Options.Covered || (FeatureMask && RequiresCovered)) {
285 NumMetadataCovered++;
286 const auto *
MI = &MetadataInfo::Covered;
288 const StringRef Section = getSectionName(
MI->SectionSuffix);
290 Constant *CFM = IRB.getInt64(FeatureMask);
291 F.setMetadata(LLVMContext::MD_pcsections,
304 return F && (
F->isIntrinsic() ||
F->doesNotReturn() ||
305 F->getName().startswith(
"__asan_") ||
306 F->getName().startswith(
"__hwsan_") ||
307 F->getName().startswith(
"__ubsan_") ||
308 F->getName().startswith(
"__msan_") ||
309 F->getName().startswith(
"__tsan_"));
312bool hasUseAfterReturnUnsafeUses(
Value &V) {
313 for (
User *U :
V.users()) {
314 if (
auto *
I = dyn_cast<Instruction>(U)) {
315 if (
I->isLifetimeStartOrEnd() ||
I->isDroppable())
317 if (
auto *CI = dyn_cast<CallInst>(U)) {
318 if (isUARSafeCall(CI))
321 if (isa<LoadInst>(U))
323 if (
auto *SI = dyn_cast<StoreInst>(U)) {
325 if (
SI->getOperand(1) == &V)
328 if (
auto *GEPI = dyn_cast<GetElementPtrInst>(U)) {
329 if (!hasUseAfterReturnUnsafeUses(*GEPI))
331 }
else if (
auto *BCI = dyn_cast<BitCastInst>(U)) {
332 if (!hasUseAfterReturnUnsafeUses(*BCI))
342 if (isa<AllocaInst>(
I))
343 return hasUseAfterReturnUnsafeUses(
I);
347 else if (
auto *CI = dyn_cast<CallInst>(&
I))
348 return CI->
isTailCall() && !isUARSafeCall(CI);
352bool SanitizerBinaryMetadata::pretendAtomicAccess(
const Value *
Addr) {
356 Addr =
Addr->stripInBoundsOffsets();
357 auto *GV = dyn_cast<GlobalVariable>(
Addr);
363 if (GV->hasSection()) {
367 if (GV->getSection().endswith(ProfSec))
370 if (GV->getName().startswith(
"__llvm_gcov") ||
371 GV->getName().startswith(
"__llvm_gcda"))
378bool maybeSharedMutable(
const Value *
Addr) {
387 Addr =
Addr->stripInBoundsOffsets();
388 if (
auto *GV = dyn_cast<GlobalVariable>(
Addr)) {
389 if (GV->isConstant())
396bool SanitizerBinaryMetadata::runOn(
Instruction &
I, MetadataInfoSet &MIS,
399 bool RequiresCovered =
false;
405 if (useAfterReturnUnsafe(
I))
411 if (
auto *SI = dyn_cast<StoreInst>(&
I))
412 Addr =
SI->getPointerOperand();
413 else if (
auto *LI = dyn_cast<LoadInst>(&
I))
414 Addr = LI->getPointerOperand();
416 if (
I.mayReadOrWriteMemory() && maybeSharedMutable(
Addr)) {
419 pretendAtomicAccess(
Addr)) {
420 NumMetadataAtomics++;
421 InstMetadata.
push_back(&MetadataInfo::Atomics);
424 RequiresCovered =
true;
429 if (!InstMetadata.
empty()) {
430 MIS.insert(InstMetadata.
begin(), InstMetadata.
end());
432 for (
const auto &
MI : InstMetadata)
433 Sections.
push_back({getSectionName(
MI->SectionSuffix), {}});
437 return RequiresCovered;
441SanitizerBinaryMetadata::getSectionMarker(
const Twine &MarkerName,
Type *Ty) {
445 GlobalVariable::ExternalWeakLinkage,
446 nullptr, MarkerName);
454 return StringPool.save(SectionSuffix +
"!C");
457Twine SanitizerBinaryMetadata::getSectionStart(
StringRef SectionSuffix) {
458 return "__start_" + SectionSuffix;
461Twine SanitizerBinaryMetadata::getSectionEnd(
StringRef SectionSuffix) {
462 return "__stop_" + SectionSuffix;
473 std::unique_ptr<SpecialCaseList> Ignorelist;
474 if (!IgnorelistFiles.
empty()) {
477 if (Ignorelist->inSection(
"metadata",
"src", M.getSourceFileName()))
481 SanitizerBinaryMetadata
Pass(M, Options, std::move(Ignorelist));
This file defines the BumpPtrAllocator interface.
Module.h This file contains the declarations for the Module class.
const char LLVMTargetMachineRef LLVMPassBuilderOptionsRef Options
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file implements a set that has insertion order iteration characteristics.
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)
Defines the virtual file system interface vfs::FileSystem.
A container for analyses that lazily runs them and caches their results.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
bool empty() const
empty - Check if the array is empty.
LLVM Basic Block Representation.
Allocate memory in an ever growing pool, as if by bump-pointer.
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
This class represents a function call, abstracting a target machine's calling convention.
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.
This is an important base class in LLVM.
void setComdat(Comdat *C)
void setLinkage(LinkageTypes LT)
@ HiddenVisibility
The GV is hidden.
void setVisibility(VisibilityTypes V)
@ ExternalLinkage
Externally visible function.
@ AvailableExternallyLinkage
Available for inspection, not emission.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
MDNode * createPCSections(ArrayRef< PCSection > Sections)
Return metadata for PC sections.
A Module instance is used to store all the information related to an LLVM module.
const std::string & getTargetTriple() const
Get the target triple which is a string describing the target host.
Comdat * getOrInsertComdat(StringRef Name)
Return the Comdat in the module with the specified name.
std::optional< CodeModel::Model > getCodeModel() const
Returns the code model (tiny, small, kernel, medium or large model)
Pass interface - Implemented by all 'passes'.
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.
A vector that has set insertion semantics.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
static std::unique_ptr< SpecialCaseList > createOrDie(const std::vector< std::string > &Paths, llvm::vfs::FileSystem &FS)
Parses the special case list entries from files.
StringRef - Represent a constant reference to a string, i.e.
Triple - Helper class for working with autoconf configuration names.
ObjectFormatType getObjectFormat() const
Get the object format for this triple.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
The instances of the Type class are immutable: once they are created, they are never changed.
static IntegerType * getInt32Ty(LLVMContext &C)
Saves strings in the provided stable storage and returns a StringRef with a stable character pointer.
LLVM Value Representation.
StringRef getName() const
Return a constant reference to the value's name.
@ SingleThread
Synchronized with respect to signal handlers executing in the same thread.
initializer< Ty > init(const Ty &Val)
IntrusiveRefCntPtr< FileSystem > getRealFileSystem()
Gets an vfs::FileSystem for the 'real' file system, as seen by the operating system.
This is an optimization pass for GlobalISel generic memory operations.
const Value * getUnderlyingObject(const Value *V, unsigned MaxLookup=6)
This method strips off any GEP address adjustments and pointer casts from the specified value,...
std::string getInstrProfSectionName(InstrProfSectKind IPSK, Triple::ObjectFormatType OF, bool AddSegmentInfo=true)
Return the name of the profile section corresponding to IPSK.
constexpr uint64_t kSanitizerBinaryMetadataUAR
std::pair< Function *, FunctionCallee > createSanitizerCtorAndInitFunctions(Module &M, StringRef CtorName, StringRef InitName, ArrayRef< Type * > InitArgTypes, ArrayRef< Value * > InitArgs, StringRef VersionCheckName=StringRef(), bool Weak=false)
Creates sanitizer constructor function, and calls sanitizer's init function from it.
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...
bool PointerMayBeCaptured(const Value *V, bool ReturnCaptures, bool StoreCaptures, unsigned MaxUsesToExplore=0)
PointerMayBeCaptured - Return true if this pointer value may be captured by the enclosing function (w...
constexpr uint64_t kSanitizerBinaryMetadataAtomics
constexpr char kSanitizerBinaryMetadataCoveredSection[]
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
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.
constexpr char kSanitizerBinaryMetadataAtomicsSection[]
void appendToGlobalDtors(Module &M, Function *F, int Priority, Constant *Data=nullptr)
Same as appendToGlobalCtors(), but for global dtors.