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"
3738#include " llvm/IR/Type.h"
39+ #include " llvm/Support/AllocToken.h"
3840#include " llvm/Support/Casting.h"
3941#include " llvm/Support/CommandLine.h"
4042#include " llvm/Support/Compiler.h"
5355#include < variant>
5456
5557using namespace llvm ;
58+ using TokenMode = AllocTokenMode;
5659
5760#define DEBUG_TYPE " alloc-token"
5861
5962namespace {
6063
61- // ===--- Constants --------------------------------------------------------===//
62-
63- enum class TokenMode : unsigned {
64- // / Incrementally increasing token ID.
65- Increment = 0 ,
66-
67- // / Simple mode that returns a statically-assigned random token ID.
68- Random = 1 ,
69-
70- // / Token ID based on allocated type hash.
71- TypeHash = 2 ,
72-
73- // / Token ID based on allocated type hash, where the top half ID-space is
74- // / reserved for types that contain pointers and the bottom half for types
75- // / that do not contain pointers.
76- TypeHashPointerSplit = 3 ,
77- };
78-
7964// ===--- Command-line options ---------------------------------------------===//
8065
8166cl::opt<TokenMode> ClMode (
@@ -131,7 +116,7 @@ cl::opt<uint64_t> ClFallbackToken(
131116
132117// ===--- Statistics -------------------------------------------------------===//
133118
134- STATISTIC (NumFunctionsInstrumented , " Functions instrumented " );
119+ STATISTIC (NumFunctionsModified , " Functions modified " );
135120STATISTIC (NumAllocationsInstrumented, " Allocations instrumented" );
136121
137122// ===----------------------------------------------------------------------===//
@@ -140,9 +125,19 @@ STATISTIC(NumAllocationsInstrumented, "Allocations instrumented");
140125// /
141126// / Expected format is: !{<type-name>, <contains-pointer>}
142127MDNode *getAllocTokenMetadata (const CallBase &CB) {
143- MDNode *Ret = CB.getMetadata (LLVMContext::MD_alloc_token);
144- if (!Ret)
145- return nullptr ;
128+ MDNode *Ret = nullptr ;
129+ if (auto *II = dyn_cast<IntrinsicInst>(&CB);
130+ II && II->getIntrinsicID () == Intrinsic::alloc_token_id) {
131+ auto *MDV = cast<MetadataAsValue>(II->getArgOperand (0 ));
132+ Ret = cast<MDNode>(MDV->getMetadata ());
133+ // If the intrinsic has an empty MDNode, type inference failed.
134+ if (Ret->getNumOperands () == 0 )
135+ return nullptr ;
136+ } else {
137+ Ret = CB.getMetadata (LLVMContext::MD_alloc_token);
138+ if (!Ret)
139+ return nullptr ;
140+ }
146141 assert (Ret->getNumOperands () == 2 && " bad !alloc_token" );
147142 assert (isa<MDString>(Ret->getOperand (0 )));
148143 assert (isa<ConstantAsMetadata>(Ret->getOperand (1 )));
@@ -206,22 +201,20 @@ class TypeHashMode : public ModeBase {
206201 using ModeBase::ModeBase;
207202
208203 uint64_t operator ()(const CallBase &CB, OptimizationRemarkEmitter &ORE) {
209- const auto [N, H] = getHash (CB, ORE);
210- return N ? boundedToken (H) : H;
211- }
212204
213- protected:
214- std::pair<MDNode *, uint64_t > getHash (const CallBase &CB,
215- OptimizationRemarkEmitter &ORE) {
216205 if (MDNode *N = getAllocTokenMetadata (CB)) {
217206 MDString *S = cast<MDString>(N->getOperand (0 ));
218- return {N, getStableSipHash (S->getString ())};
207+ AllocTokenMetadata Metadata{S->getString (), containsPointer (N)};
208+ if (auto Token =
209+ getAllocTokenHash (TokenMode::TypeHash, Metadata, MaxTokens))
210+ return *Token;
219211 }
220212 // Fallback.
221213 remarkNoMetadata (CB, ORE);
222- return { nullptr , ClFallbackToken} ;
214+ return ClFallbackToken;
223215 }
224216
217+ protected:
225218 // / Remark that there was no precise type information.
226219 static void remarkNoMetadata (const CallBase &CB,
227220 OptimizationRemarkEmitter &ORE) {
@@ -242,20 +235,18 @@ class TypeHashPointerSplitMode : public TypeHashMode {
242235 using TypeHashMode::TypeHashMode;
243236
244237 uint64_t operator ()(const CallBase &CB, OptimizationRemarkEmitter &ORE) {
245- if (MaxTokens == 1 )
246- return 0 ;
247- const uint64_t HalfTokens = MaxTokens / 2 ;
248- const auto [N, H] = getHash (CB, ORE);
249- if (!N) {
250- // Pick the fallback token (ClFallbackToken), which by default is 0,
251- // meaning it'll fall into the pointer-less bucket. Override by setting
252- // -alloc-token-fallback if that is the wrong choice.
253- return H;
238+ if (MDNode *N = getAllocTokenMetadata (CB)) {
239+ MDString *S = cast<MDString>(N->getOperand (0 ));
240+ AllocTokenMetadata Metadata{S->getString (), containsPointer (N)};
241+ if (auto Token = getAllocTokenHash (TokenMode::TypeHashPointerSplit,
242+ Metadata, MaxTokens))
243+ return *Token;
254244 }
255- uint64_t Hash = H % HalfTokens; // base hash
256- if (containsPointer (N))
257- Hash += HalfTokens;
258- return Hash;
245+ // Pick the fallback token (ClFallbackToken), which by default is 0, meaning
246+ // it'll fall into the pointer-less bucket. Override by setting
247+ // -alloc-token-fallback if that is the wrong choice.
248+ remarkNoMetadata (CB, ORE);
249+ return ClFallbackToken;
259250 }
260251};
261252
@@ -315,6 +306,9 @@ class AllocToken {
315306 FunctionCallee getTokenAllocFunction (const CallBase &CB, uint64_t TokenID,
316307 LibFunc OriginalFunc);
317308
309+ // / Lower alloc_token_* intrinsics.
310+ void replaceIntrinsicInst (IntrinsicInst *II, OptimizationRemarkEmitter &ORE);
311+
318312 // / Return the token ID from metadata in the call.
319313 uint64_t getToken (const CallBase &CB, OptimizationRemarkEmitter &ORE) {
320314 return std::visit ([&](auto &&Mode) { return Mode (CB, ORE); }, Mode);
@@ -336,21 +330,32 @@ bool AllocToken::instrumentFunction(Function &F) {
336330 // Do not apply any instrumentation for naked functions.
337331 if (F.hasFnAttribute (Attribute::Naked))
338332 return false ;
339- if (F.hasFnAttribute (Attribute::DisableSanitizerInstrumentation))
340- return false ;
341333 // Don't touch available_externally functions, their actual body is elsewhere.
342334 if (F.getLinkage () == GlobalValue::AvailableExternallyLinkage)
343335 return false ;
344- // Only instrument functions that have the sanitize_alloc_token attribute.
345- if (!F.hasFnAttribute (Attribute::SanitizeAllocToken))
346- return false ;
347336
348337 auto &ORE = FAM.getResult <OptimizationRemarkEmitterAnalysis>(F);
349338 auto &TLI = FAM.getResult <TargetLibraryAnalysis>(F);
350339 SmallVector<std::pair<CallBase *, LibFunc>, 4 > AllocCalls;
340+ SmallVector<IntrinsicInst *, 4 > IntrinsicInsts;
341+
342+ // Only instrument functions that have the sanitize_alloc_token attribute.
343+ const bool InstrumentFunction =
344+ F.hasFnAttribute (Attribute::SanitizeAllocToken) &&
345+ !F.hasFnAttribute (Attribute::DisableSanitizerInstrumentation);
351346
352347 // Collect all allocation calls to avoid iterator invalidation.
353348 for (Instruction &I : instructions (F)) {
349+ // Collect all alloc_token_* intrinsics.
350+ if (auto *II = dyn_cast<IntrinsicInst>(&I);
351+ II && II->getIntrinsicID () == Intrinsic::alloc_token_id) {
352+ IntrinsicInsts.emplace_back (II);
353+ continue ;
354+ }
355+
356+ if (!InstrumentFunction)
357+ continue ;
358+
354359 auto *CB = dyn_cast<CallBase>(&I);
355360 if (!CB)
356361 continue ;
@@ -359,11 +364,22 @@ bool AllocToken::instrumentFunction(Function &F) {
359364 }
360365
361366 bool Modified = false ;
362- for (auto &[CB, Func] : AllocCalls)
363- Modified |= replaceAllocationCall (CB, Func, ORE, TLI);
364367
365- if (Modified)
366- NumFunctionsInstrumented++;
368+ if (!AllocCalls.empty ()) {
369+ for (auto &[CB, Func] : AllocCalls)
370+ Modified |= replaceAllocationCall (CB, Func, ORE, TLI);
371+ if (Modified)
372+ NumFunctionsModified++;
373+ }
374+
375+ if (!IntrinsicInsts.empty ()) {
376+ for (auto *II : IntrinsicInsts) {
377+ replaceIntrinsicInst (II, ORE);
378+ }
379+ Modified = true ;
380+ NumFunctionsModified++;
381+ }
382+
367383 return Modified;
368384}
369385
@@ -528,6 +544,16 @@ FunctionCallee AllocToken::getTokenAllocFunction(const CallBase &CB,
528544 return TokenAlloc;
529545}
530546
547+ void AllocToken::replaceIntrinsicInst (IntrinsicInst *II,
548+ OptimizationRemarkEmitter &ORE) {
549+ assert (II->getIntrinsicID () == Intrinsic::alloc_token_id);
550+
551+ uint64_t TokenID = getToken (*II, ORE);
552+ Value *V = ConstantInt::get (IntPtrTy, TokenID);
553+ II->replaceAllUsesWith (V);
554+ II->eraseFromParent ();
555+ }
556+
531557} // namespace
532558
533559AllocTokenPass::AllocTokenPass (AllocTokenOptions Opts)
0 commit comments