52#define DEBUG_TYPE "sanmd"
59constexpr uint32_t kVersionPtrSizeRel = (1u << 16);
60constexpr int kCtorDtorPriority = 2;
69 static const MetadataInfo Covered;
70 static const MetadataInfo Atomics;
74 explicit constexpr MetadataInfo(
StringRef FunctionPrefix,
76 : FunctionPrefix(FunctionPrefix), SectionSuffix(SectionSuffix) {}
78const MetadataInfo MetadataInfo::Covered{
80const MetadataInfo MetadataInfo::Atomics{
91 "sanitizer-metadata-weak-callbacks",
92 cl::desc(
"Declare callbacks extern weak, and only call if non-null."),
95 ClNoSanitize(
"sanitizer-metadata-nosanitize-attr",
96 cl::desc(
"Mark some metadata features uncovered in functions "
97 "with associated no_sanitize attributes."),
101 cl::desc(
"Emit PCs for covered functions."),
104 cl::desc(
"Emit PCs for atomic operations."),
107 cl::desc(
"Emit PCs for start of functions that are "
108 "subject for use-after-return checking"),
113STATISTIC(NumMetadataCovered,
"Metadata attached to covered functions");
114STATISTIC(NumMetadataAtomics,
"Metadata attached to atomics");
115STATISTIC(NumMetadataUAR,
"Metadata attached to UAR functions");
123 Opts.Atomics |= ClEmitAtomics;
124 Opts.UAR |= ClEmitUAR;
125 return std::move(Opts);
128class SanitizerBinaryMetadata {
131 std::unique_ptr<SpecialCaseList> Ignorelist)
132 :
Mod(M), Options(transformOptionsFromCl(std::move(Opts))),
133 Ignorelist(std::move(Ignorelist)), TargetTriple(M.getTargetTriple()),
134 VersionStr(utostr(getVersion())), IRB(M.getContext()) {
136 assert(TargetTriple.isOSBinFormatELF() &&
"ELF only");
137 assert(!(TargetTriple.isNVPTX() || TargetTriple.isAMDGPU()) &&
138 "Device targets are not supported");
146 const auto CM =
Mod.getCodeModel();
148 Version |= kVersionPtrSizeRel;
152 void runOn(
Function &
F, MetadataInfoSet &MIS);
177 bool pretendAtomicAccess(
const Value *
Addr);
181 std::unique_ptr<SpecialCaseList> Ignorelist;
182 const Triple TargetTriple;
183 const std::string VersionStr;
189bool SanitizerBinaryMetadata::run() {
203 auto *PtrTy = IRB.getPtrTy();
204 auto *Int32Ty = IRB.getInt32Ty();
205 const std::array<Type *, 3> InitTypes = {Int32Ty, PtrTy, PtrTy};
206 auto *Version = ConstantInt::get(Int32Ty, getVersion());
208 for (
const MetadataInfo *
MI : MIS) {
209 const std::array<
Value *, InitTypes.size()> InitArgs = {
211 getSectionMarker(getSectionStart(
MI->SectionSuffix), PtrTy),
212 getSectionMarker(getSectionEnd(
MI->SectionSuffix), PtrTy),
218 const std::string StructorPrefix = (
MI->FunctionPrefix + VersionStr).str();
226 Mod, StructorPrefix +
".module_ctor",
227 (
MI->FunctionPrefix +
"_add").str(), InitTypes, InitArgs,
232 Mod, StructorPrefix +
".module_dtor",
233 (
MI->FunctionPrefix +
"_del").str(), InitTypes, InitArgs,
238 if (TargetTriple.supportsCOMDAT()) {
248 CtorComdatKey = Ctor;
249 DtorComdatKey = Dtor;
258void SanitizerBinaryMetadata::runOn(
Function &
F, MetadataInfoSet &MIS) {
261 if (
F.hasFnAttribute(Attribute::DisableSanitizerInstrumentation))
263 if (Ignorelist && Ignorelist->inSection(
"metadata",
"fun",
F.getName()))
275 bool RequiresCovered =
false;
280 RequiresCovered |= runOn(
I, MIS, MDB, FeatureMask);
283 if (ClNoSanitize &&
F.hasFnAttribute(
"no_sanitize_thread"))
284 FeatureMask &= ~kSanitizerBinaryMetadataAtomics;
286 FeatureMask &= ~kSanitizerBinaryMetadataUAR;
288 RequiresCovered =
true;
295 if (
Options.Covered || (FeatureMask && RequiresCovered)) {
296 NumMetadataCovered++;
297 const auto *
MI = &MetadataInfo::Covered;
301 Constant *CFM = IRB.getInt64(FeatureMask);
302 F.setMetadata(LLVMContext::MD_pcsections,
315 return F && (
F->isIntrinsic() ||
F->doesNotReturn() ||
316 F->getName().starts_with(
"__asan_") ||
317 F->getName().starts_with(
"__hwsan_") ||
318 F->getName().starts_with(
"__ubsan_") ||
319 F->getName().starts_with(
"__msan_") ||
320 F->getName().starts_with(
"__tsan_"));
323bool hasUseAfterReturnUnsafeUses(
Value &V) {
324 for (
User *U :
V.users()) {
325 if (
auto *
I = dyn_cast<Instruction>(U)) {
326 if (
I->isLifetimeStartOrEnd() ||
I->isDroppable())
328 if (
auto *CI = dyn_cast<CallInst>(U)) {
329 if (isUARSafeCall(CI))
332 if (isa<LoadInst>(U))
334 if (
auto *SI = dyn_cast<StoreInst>(U)) {
336 if (
SI->getOperand(1) == &V)
339 if (
auto *GEPI = dyn_cast<GetElementPtrInst>(U)) {
340 if (!hasUseAfterReturnUnsafeUses(*GEPI))
342 }
else if (
auto *BCI = dyn_cast<BitCastInst>(U)) {
343 if (!hasUseAfterReturnUnsafeUses(*BCI))
353 if (isa<AllocaInst>(
I))
354 return hasUseAfterReturnUnsafeUses(
I);
358 else if (
auto *CI = dyn_cast<CallInst>(&
I))
359 return CI->
isTailCall() && !isUARSafeCall(CI);
363bool SanitizerBinaryMetadata::pretendAtomicAccess(
const Value *
Addr) {
367 Addr =
Addr->stripInBoundsOffsets();
368 auto *GV = dyn_cast<GlobalVariable>(
Addr);
374 if (GV->hasSection()) {
378 if (GV->getSection().ends_with(ProfSec))
381 if (GV->getName().starts_with(
"__llvm_gcov") ||
382 GV->getName().starts_with(
"__llvm_gcda"))
389bool maybeSharedMutable(
const Value *
Addr) {
398 Addr =
Addr->stripInBoundsOffsets();
399 if (
auto *GV = dyn_cast<GlobalVariable>(
Addr)) {
400 if (GV->isConstant())
407bool SanitizerBinaryMetadata::runOn(
Instruction &
I, MetadataInfoSet &MIS,
410 bool RequiresCovered =
false;
416 if (useAfterReturnUnsafe(
I))
422 if (
auto *SI = dyn_cast<StoreInst>(&
I))
423 Addr =
SI->getPointerOperand();
424 else if (
auto *LI = dyn_cast<LoadInst>(&
I))
425 Addr = LI->getPointerOperand();
427 if (
I.mayReadOrWriteMemory() && maybeSharedMutable(
Addr)) {
430 pretendAtomicAccess(
Addr)) {
431 NumMetadataAtomics++;
432 InstMetadata.
push_back(&MetadataInfo::Atomics);
435 RequiresCovered =
true;
440 if (!InstMetadata.
empty()) {
441 MIS.insert(InstMetadata.
begin(), InstMetadata.
end());
443 for (
const auto &
MI : InstMetadata)
448 return RequiresCovered;
452SanitizerBinaryMetadata::getSectionMarker(
const Twine &MarkerName,
Type *Ty) {
456 GlobalVariable::ExternalWeakLinkage,
457 nullptr, MarkerName);
465 return StringPool.save(SectionSuffix + VersionStr +
"!C");
473 return StringPool.save(
"__start_" + SectionSuffix + VersionStr);
477 return StringPool.save(
"__stop_" + SectionSuffix + VersionStr);
488 std::unique_ptr<SpecialCaseList> Ignorelist;
489 if (!IgnorelistFiles.
empty()) {
492 if (Ignorelist->inSection(
"metadata",
"src", M.getSourceFileName()))
496 SanitizerBinaryMetadata
Pass(M, Options, std::move(Ignorelist));
This file defines the BumpPtrAllocator interface.
Module.h This file contains the declarations for the Module class.
if(auto Err=PB.parsePassPipeline(MPM, Passes)) return wrap(std MPM run * Mod
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.
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.
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.
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)
static constexpr const StringLiteral & getSectionName(DebugSectionKind SectionKind)
Return the name of the section.
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, pointer casts or llvm.threadlocal....
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.
Implement std::hash so that hash_code can be used in STL containers.