3131#include " llvm/IR/InstIterator.h"
3232#include " llvm/IR/InstrTypes.h"
3333#include " llvm/IR/Instructions.h"
34+ #include " llvm/IR/IntrinsicInst.h"
3435#include " llvm/IR/Metadata.h"
3536#include " llvm/IR/Module.h"
3637#include " llvm/IR/PassManager.h"
@@ -131,7 +132,7 @@ cl::opt<uint64_t> ClFallbackToken(
131132
132133// ===--- Statistics -------------------------------------------------------===//
133134
134- STATISTIC (NumFunctionsInstrumented , " Functions instrumented " );
135+ STATISTIC (NumFunctionsModified , " Functions modified " );
135136STATISTIC (NumAllocationsInstrumented, " Allocations instrumented" );
136137
137138// ===----------------------------------------------------------------------===//
@@ -140,9 +141,19 @@ STATISTIC(NumAllocationsInstrumented, "Allocations instrumented");
140141// /
141142// / Expected format is: !{<type-name>, <contains-pointer>}
142143MDNode *getAllocTokenMetadata (const CallBase &CB) {
143- MDNode *Ret = CB.getMetadata (LLVMContext::MD_alloc_token);
144- if (!Ret)
145- return nullptr ;
144+ MDNode *Ret = nullptr ;
145+ if (auto *II = dyn_cast<IntrinsicInst>(&CB);
146+ II && II->getIntrinsicID () == Intrinsic::alloc_token_id) {
147+ auto *MDV = cast<MetadataAsValue>(II->getArgOperand (0 ));
148+ Ret = cast<MDNode>(MDV->getMetadata ());
149+ // If the intrinsic has an empty MDNode, type inference failed.
150+ if (Ret->getNumOperands () == 0 )
151+ return nullptr ;
152+ } else {
153+ Ret = CB.getMetadata (LLVMContext::MD_alloc_token);
154+ if (!Ret)
155+ return nullptr ;
156+ }
146157 assert (Ret->getNumOperands () == 2 && " bad !alloc_token" );
147158 assert (isa<MDString>(Ret->getOperand (0 )));
148159 assert (isa<ConstantAsMetadata>(Ret->getOperand (1 )));
@@ -315,6 +326,9 @@ class AllocToken {
315326 FunctionCallee getTokenAllocFunction (const CallBase &CB, uint64_t TokenID,
316327 LibFunc OriginalFunc);
317328
329+ // / Lower alloc_token_* intrinsics.
330+ void replaceIntrinsicInst (IntrinsicInst *II, OptimizationRemarkEmitter &ORE);
331+
318332 // / Return the token ID from metadata in the call.
319333 uint64_t getToken (const CallBase &CB, OptimizationRemarkEmitter &ORE) {
320334 return std::visit ([&](auto &&Mode) { return Mode (CB, ORE); }, Mode);
@@ -336,21 +350,32 @@ bool AllocToken::instrumentFunction(Function &F) {
336350 // Do not apply any instrumentation for naked functions.
337351 if (F.hasFnAttribute (Attribute::Naked))
338352 return false ;
339- if (F.hasFnAttribute (Attribute::DisableSanitizerInstrumentation))
340- return false ;
341353 // Don't touch available_externally functions, their actual body is elsewhere.
342354 if (F.getLinkage () == GlobalValue::AvailableExternallyLinkage)
343355 return false ;
344- // Only instrument functions that have the sanitize_alloc_token attribute.
345- if (!F.hasFnAttribute (Attribute::SanitizeAllocToken))
346- return false ;
347356
348357 auto &ORE = FAM.getResult <OptimizationRemarkEmitterAnalysis>(F);
349358 auto &TLI = FAM.getResult <TargetLibraryAnalysis>(F);
350359 SmallVector<std::pair<CallBase *, LibFunc>, 4 > AllocCalls;
360+ SmallVector<IntrinsicInst *, 4 > IntrinsicInsts;
361+
362+ // Only instrument functions that have the sanitize_alloc_token attribute.
363+ const bool InstrumentFunction =
364+ F.hasFnAttribute (Attribute::SanitizeAllocToken) &&
365+ !F.hasFnAttribute (Attribute::DisableSanitizerInstrumentation);
351366
352367 // Collect all allocation calls to avoid iterator invalidation.
353368 for (Instruction &I : instructions (F)) {
369+ // Collect all alloc_token_* intrinsics.
370+ if (auto *II = dyn_cast<IntrinsicInst>(&I);
371+ II && II->getIntrinsicID () == Intrinsic::alloc_token_id) {
372+ IntrinsicInsts.emplace_back (II);
373+ continue ;
374+ }
375+
376+ if (!InstrumentFunction)
377+ continue ;
378+
354379 auto *CB = dyn_cast<CallBase>(&I);
355380 if (!CB)
356381 continue ;
@@ -359,11 +384,21 @@ bool AllocToken::instrumentFunction(Function &F) {
359384 }
360385
361386 bool Modified = false ;
362- for (auto &[CB, Func] : AllocCalls)
363- Modified |= replaceAllocationCall (CB, Func, ORE, TLI);
364387
365- if (Modified)
366- NumFunctionsInstrumented++;
388+ if (!AllocCalls.empty ()) {
389+ for (auto &[CB, Func] : AllocCalls)
390+ Modified |= replaceAllocationCall (CB, Func, ORE, TLI);
391+ if (Modified)
392+ NumFunctionsModified++;
393+ }
394+
395+ if (!IntrinsicInsts.empty ()) {
396+ for (auto *II : IntrinsicInsts)
397+ replaceIntrinsicInst (II, ORE);
398+ Modified = true ;
399+ NumFunctionsModified++;
400+ }
401+
367402 return Modified;
368403}
369404
@@ -381,7 +416,7 @@ AllocToken::shouldInstrumentCall(const CallBase &CB,
381416 if (TLI.getLibFunc (*Callee, Func)) {
382417 if (isInstrumentableLibFunc (Func, CB, TLI))
383418 return Func;
384- } else if (Options.Extended && getAllocTokenMetadata (CB )) {
419+ } else if (Options.Extended && CB. getMetadata (LLVMContext::MD_alloc_token )) {
385420 return NotLibFunc;
386421 }
387422
@@ -528,6 +563,16 @@ FunctionCallee AllocToken::getTokenAllocFunction(const CallBase &CB,
528563 return TokenAlloc;
529564}
530565
566+ void AllocToken::replaceIntrinsicInst (IntrinsicInst *II,
567+ OptimizationRemarkEmitter &ORE) {
568+ assert (II->getIntrinsicID () == Intrinsic::alloc_token_id);
569+
570+ uint64_t TokenID = getToken (*II, ORE);
571+ Value *V = ConstantInt::get (IntPtrTy, TokenID);
572+ II->replaceAllUsesWith (V);
573+ II->eraseFromParent ();
574+ }
575+
531576} // namespace
532577
533578AllocTokenPass::AllocTokenPass (AllocTokenOptions Opts)
0 commit comments