LLVM: lib/Transforms/Instrumentation/AllocToken.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

47#include

48#include

49#include

50#include

51#include

52#include

53#include

54#include

55#include

56

57using namespace llvm;

59

60#define DEBUG_TYPE "alloc-token"

61

62namespace {

63

64

65

67 cl::desc("The allocation function prefix"),

69

71 ClMaxTokens("alloc-token-max",

72 cl::desc("Maximum number of tokens (0 = target SIZE_MAX)"),

74

76 ClFastABI("alloc-token-fast-abi",

77 cl::desc("The token ID is encoded in the function name"),

79

80

81

82

83

85 ClExtended("alloc-token-extended",

86 cl::desc("Extend coverage to custom allocation functions"),

88

89

90

91

92

93cl::opt ClCoverReplaceableNew("alloc-token-cover-replaceable-new",

94 cl::desc("Cover replaceable operator new"),

96

98 "alloc-token-fallback",

99 cl::desc("The default fallback token where none could be determined"),

101

102

103

104STATISTIC(NumFunctionsModified, "Functions modified");

105STATISTIC(NumAllocationsInstrumented, "Allocations instrumented");

106

107

108

109

110

111

113 MDNode *Ret = nullptr;

115 II && II->getIntrinsicID() == Intrinsic::alloc_token_id) {

118

120 return nullptr;

121 } else {

122 Ret = CB.getMetadata(LLVMContext::MD_alloc_token);

123 if (!Ret)

124 return nullptr;

125 }

129 return Ret;

130}

131

132bool containsPointer(const MDNode *MD) {

135 return CI->getValue().getBoolValue();

136}

137

138class ModeBase {

139public:

141 : MaxTokens(MaxTokens ? MaxTokens : TokenTy.getBitMask()) {

143 }

144

145protected:

147 assert(MaxTokens != 0);

148 return Val % MaxTokens;

149 }

150

152};

153

154

155class IncrementMode : public ModeBase {

156public:

157 using ModeBase::ModeBase;

158

160 return boundedToken(Counter++);

161 }

162

163private:

165};

166

167

168class RandomMode : public ModeBase {

169public:

171 std::unique_ptr RNG)

172 : ModeBase(TokenTy, MaxTokens), RNG(std::move(RNG)) {}

174 return boundedToken((*RNG)());

175 }

176

177private:

178 std::unique_ptr RNG;

179};

180

181

182

183

184class TypeHashMode : public ModeBase {

185public:

186 using ModeBase::ModeBase;

187

189

190 if (MDNode *N = getAllocTokenMetadata(CB)) {

194 return *Token;

195 }

196

197 remarkNoMetadata(CB, ORE);

198 return ClFallbackToken;

199 }

200

201protected:

202

203 static void remarkNoMetadata(const CallBase &CB,

205 ORE.emit([&] {

208 ore::NV CalleeNV("Callee", Callee ? Callee->getName() : "");

210 << "Call to '" << CalleeNV << "' in '" << FuncNV

211 << "' without source-level type token";

212 });

213 }

214};

215

216

217class TypeHashPointerSplitMode : public TypeHashMode {

218public:

219 using TypeHashMode::TypeHashMode;

220

222 if (MDNode *N = getAllocTokenMetadata(CB)) {

226 MaxTokens))

227 return *Token;

228 }

229

230

231

232 remarkNoMetadata(CB, ORE);

233 return ClFallbackToken;

234 }

235};

236

237

240 auto IntModuleFlagOrNull = [&](StringRef Key) {

242 };

243

247 if (auto *Val = IntModuleFlagOrNull("alloc-token-max"))

248 Opts.MaxTokens = Val->getZExtValue();

249 if (auto *Val = IntModuleFlagOrNull("alloc-token-fast-abi"))

250 Opts.FastABI |= Val->isOne();

251 if (auto *Val = IntModuleFlagOrNull("alloc-token-extended"))

252 Opts.Extended |= Val->isOne();

253

254

258 Opts.FastABI = ClFastABI;

261

262 return Opts;

263}

264

265class AllocToken {

266public:

269 : Options(resolveOptions(std::move(Opts), M)), Mod(M),

271 Mode(IncrementMode(*IntPtrTy, Options.MaxTokens)) {

274 break;

276 Mode.emplace(*IntPtrTy, Options.MaxTokens,

278 break;

280 Mode.emplace(*IntPtrTy, Options.MaxTokens);

281 break;

283 Mode.emplace(*IntPtrTy, Options.MaxTokens);

284 break;

285 }

286 }

287

288 bool instrumentFunction(Function &F);

289

290private:

291

292 std::optional

294

295

296 static bool isInstrumentableLibFunc(LibFunc Func, const CallBase &CB,

298

299

300 static bool ignoreInstrumentableLibFunc(LibFunc Func);

301

302

303

304 bool replaceAllocationCall(CallBase *CB, LibFunc Func,

307

308

310 LibFunc OriginalFunc);

311

312

314

315

317 return std::visit([&](auto &&Mode) { return Mode(CB, ORE); }, Mode);

318 }

319

322 IntegerType *IntPtrTy = Mod.getDataLayout().getIntPtrType(Mod.getContext());

324

326

327 std::variant<IncrementMode, RandomMode, TypeHashMode,

328 TypeHashPointerSplitMode>

330};

331

332bool AllocToken::instrumentFunction(Function &F) {

333

334 if (F.hasFnAttribute(Attribute::Naked))

335 return false;

336

338 return false;

339

342

343

344 const bool InstrumentFunction =

345 F.hasFnAttribute(Attribute::SanitizeAllocToken) &&

346 F.hasFnAttribute(Attribute::DisableSanitizerInstrumentation);

347

348

351

352

354

356 II && II->getIntrinsicID() == Intrinsic::alloc_token_id) {

358 continue;

359 }

360

361 if (!InstrumentFunction)

362 continue;

363

365 if (!CB)

366 continue;

367 if (std::optional Func = shouldInstrumentCall(*CB, *TLI))

369 }

370

371

372 if (AllocCalls.empty() && IntrinsicInsts.empty())

373 return false;

374

377

378 for (auto &[CB, Func] : AllocCalls)

379 Modified |= replaceAllocationCall(CB, Func, ORE, *TLI);

380

381 for (auto *II : IntrinsicInsts) {

382 replaceIntrinsicInst(II, ORE);

384 }

385

387 NumFunctionsModified++;

388

390}

391

392std::optional

393AllocToken::shouldInstrumentCall(const CallBase &CB,

396 if (!Callee)

397 return std::nullopt;

398

399

400

401

402 LibFunc Func;

404 if (isInstrumentableLibFunc(Func, CB, TLI))

405 return Func;

406 } else if (Options.Extended && CB.getMetadata(LLVMContext::MD_alloc_token)) {

407 return NotLibFunc;

408 }

409

410 return std::nullopt;

411}

412

413bool AllocToken::isInstrumentableLibFunc(LibFunc Func, const CallBase &CB,

415 if (ignoreInstrumentableLibFunc(Func))

416 return false;

417

419 return true;

420

421 switch (Func) {

422

423

424 case LibFunc_posix_memalign:

425 case LibFunc_size_returning_new:

426 case LibFunc_size_returning_new_hot_cold:

427 case LibFunc_size_returning_new_aligned:

428 case LibFunc_size_returning_new_aligned_hot_cold:

429 return true;

430

431

432 case LibFunc_Znwj:

433 case LibFunc_ZnwjRKSt9nothrow_t:

434 case LibFunc_ZnwjSt11align_val_t:

435 case LibFunc_ZnwjSt11align_val_tRKSt9nothrow_t:

436 case LibFunc_Znwm:

437 case LibFunc_Znwm12__hot_cold_t:

438 case LibFunc_ZnwmRKSt9nothrow_t:

439 case LibFunc_ZnwmRKSt9nothrow_t12__hot_cold_t:

440 case LibFunc_ZnwmSt11align_val_t:

441 case LibFunc_ZnwmSt11align_val_t12__hot_cold_t:

442 case LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t:

443 case LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t12__hot_cold_t:

444 case LibFunc_Znaj:

445 case LibFunc_ZnajRKSt9nothrow_t:

446 case LibFunc_ZnajSt11align_val_t:

447 case LibFunc_ZnajSt11align_val_tRKSt9nothrow_t:

448 case LibFunc_Znam:

449 case LibFunc_Znam12__hot_cold_t:

450 case LibFunc_ZnamRKSt9nothrow_t:

451 case LibFunc_ZnamRKSt9nothrow_t12__hot_cold_t:

452 case LibFunc_ZnamSt11align_val_t:

453 case LibFunc_ZnamSt11align_val_t12__hot_cold_t:

454 case LibFunc_ZnamSt11align_val_tRKSt9nothrow_t:

455 case LibFunc_ZnamSt11align_val_tRKSt9nothrow_t12__hot_cold_t:

456 return ClCoverReplaceableNew;

457

458 default:

459 return false;

460 }

461}

462

463bool AllocToken::ignoreInstrumentableLibFunc(LibFunc Func) {

464 switch (Func) {

465 case LibFunc_strdup:

466 case LibFunc_dunder_strdup:

467 case LibFunc_strndup:

468 case LibFunc_dunder_strndup:

469 return true;

470 default:

471 return false;

472 }

473}

474

475bool AllocToken::replaceAllocationCall(CallBase *CB, LibFunc Func,

479

480 FunctionCallee TokenAlloc = getTokenAllocFunction(*CB, TokenID, Func);

481 if (!TokenAlloc)

482 return false;

483 NumAllocationsInstrumented++;

484

488 return true;

489 }

490

492

494

495 NewArgs.push_back(ConstantInt::get(IntPtrTy, TokenID));

497

498

501 NewCall = IRB.CreateInvoke(TokenAlloc, II->getNormalDest(),

502 II->getUnwindDest(), NewArgs);

503 } else {

504 NewCall = IRB.CreateCall(TokenAlloc, NewArgs);

506 }

510

511

514 return true;

515}

516

519 LibFunc OriginalFunc) {

520 std::optional<std::pair<LibFunc, uint64_t>> Key;

521 if (OriginalFunc != NotLibFunc) {

522 Key = std::make_pair(OriginalFunc, Options.FastABI ? TokenID : 0);

523 auto It = TokenAllocFunctions.find(*Key);

524 if (It != TokenAllocFunctions.end())

525 return It->second;

526 }

527

529 if (!Callee)

531 const FunctionType *OldFTy = Callee->getFunctionType();

532 if (OldFTy->isVarArg())

534

535 Type *RetTy = OldFTy->getReturnType();

537 std::string TokenAllocName = ClFuncPrefix;

539 TokenAllocName += utostr(TokenID) + "_";

540 else

541 NewParams.push_back(IntPtrTy);

542 TokenAllocName += Callee->getName();

544 FunctionCallee TokenAlloc = Mod.getOrInsertFunction(TokenAllocName, NewFTy);

546 F->copyAttributesFrom(Callee);

547

548 if (Key.has_value())

549 TokenAllocFunctions[*Key] = TokenAlloc;

550 return TokenAlloc;

551}

552

555 assert(II->getIntrinsicID() == Intrinsic::alloc_token_id);

556

558 Value *V = ConstantInt::get(IntPtrTy, TokenID);

559 II->replaceAllUsesWith(V);

560 II->eraseFromParent();

561}

562

563}

564

567

569 AllocToken Pass(Options, M, MAM);

571

573 if (F.empty())

574 continue;

576 }

577

580}

assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")

Expand Atomic instructions

This file contains the simple types necessary to represent the attributes associated with functions a...

This file contains the declarations for the subclasses of Constant, which represent the different fla...

This file defines the DenseMap class.

Module.h This file contains the declarations for the Module class.

This header defines various interfaces for pass management in LLVM.

print mir2vec MIR2Vec Vocabulary Printer Pass

uint64_t IntrinsicInst * II

if(auto Err=PB.parsePassPipeline(MPM, Passes)) return wrap(std MPM run * Mod

FunctionAnalysisManager FAM

ModuleAnalysisManager MAM

static cl::opt< RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode > Mode("regalloc-enable-advisor", cl::Hidden, cl::init(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Default), cl::desc("Enable regalloc advisor mode"), cl::values(clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Default, "default", "Default"), clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Release, "release", "precompiled"), clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Development, "development", "for training")))

This file defines the SmallPtrSet class.

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)

AllocTokenMode TokenMode

Definition AllocToken.cpp:58

LLVM_ABI AllocTokenPass(AllocTokenOptions Opts={})

Definition AllocToken.cpp:565

LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)

Definition AllocToken.cpp:568

Represents analyses that only rely on functions' control flow.

Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...

void setCallingConv(CallingConv::ID CC)

Function * getCalledFunction() const

Returns the function called, or null if this is an indirect function invocation or the function signa...

CallingConv::ID getCallingConv() const

void setAttributes(AttributeList A)

Set the attributes for this call.

iterator_range< User::op_iterator > args()

Iteration adapter for range-for loops.

unsigned arg_size() const

AttributeList getAttributes() const

Return the attributes for this call.

void setCalledFunction(Function *Fn)

Sets the function called, including updating the function type.

LLVM_ABI bool isTailCall() const

Tests if this call site is marked as a tail call.

void setTailCall(bool IsTc=true)

A handy container for a FunctionType+Callee-pointer pair, which can be passed around as a single enti...

FunctionType * getFunctionType()

unsigned getNumParams() const

Return the number of fixed parameters this function type requires.

static LLVM_ABI FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)

This static method is the primary way of constructing a FunctionType.

@ AvailableExternallyLinkage

Available for inspection, not emission.

InvokeInst * CreateInvoke(FunctionType *Ty, Value *Callee, BasicBlock *NormalDest, BasicBlock *UnwindDest, ArrayRef< Value * > Args, ArrayRef< OperandBundleDef > OpBundles, const Twine &Name="")

Create an invoke instruction.

CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args={}, const Twine &Name="", MDNode *FPMathTag=nullptr)

This provides a uniform API for creating instructions and inserting them into a basic block: either a...

LLVM_ABI InstListType::iterator eraseFromParent()

This method unlinks 'this' from the containing basic block and deletes it.

MDNode * getMetadata(unsigned KindID) const

Get the metadata of given kind attached to this Instruction.

LLVM_ABI void copyMetadata(const Instruction &SrcInst, ArrayRef< unsigned > WL=ArrayRef< unsigned >())

Copy metadata from SrcInst to this instruction.

Class to represent integer types.

uint64_t getBitMask() const

Return a bitmask with ones set for all of the bits that can be set by an unsigned version of this typ...

A wrapper class for inspecting calls to intrinsic functions.

const MDOperand & getOperand(unsigned I) const

unsigned getNumOperands() const

Return number of MDNode operands.

LLVM_ABI StringRef getString() const

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.

PreservedAnalyses & preserveSet()

Mark an analysis set as preserved.

reference emplace_back(ArgTypes &&... Args)

void push_back(const T &Elt)

This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.

StringRef - 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.

bool getLibFunc(StringRef funcName, LibFunc &F) const

Searches for a particular function name.

The instances of the Type class are immutable: once they are created, they are never changed.

LLVM Value Representation.

LLVM_ABI void replaceAllUsesWith(Value *V)

Change all uses of this to point to a new Value.

int getNumOccurrences() const

const ParentTy * getParent() const

Pass manager infrastructure for declaring and invalidating analyses.

@ C

The default llvm calling convention, compatible with C.

initializer< Ty > init(const Ty &Val)

std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > extract_or_null(Y &&MD)

Extract a Value from Metadata, allowing null.

DiagnosticInfoOptimizationBase::Argument NV

This is an optimization pass for GlobalISel generic memory operations.

LLVM_ABI std::optional< uint64_t > getAllocToken(AllocTokenMode Mode, const AllocTokenMetadata &Metadata, uint64_t MaxTokens)

Calculates stable allocation token ID.

LLVM_ABI std::pair< StringRef, StringRef > getToken(StringRef Source, StringRef Delimiters=" \t\n\v\f\r")

getToken - This function extracts one token from source, ignoring any leading characters that appear ...

decltype(auto) dyn_cast(const From &Val)

dyn_cast - Return the argument parameter cast to the specified type.

InnerAnalysisManagerProxy< FunctionAnalysisManager, Module > FunctionAnalysisManagerModuleProxy

Provide the FunctionAnalysisManager to Module proxy.

std::string utostr(uint64_t X, bool isNeg=false)

auto dyn_cast_or_null(const Y &Val)

bool isa(const From &Val)

isa - Return true if the parameter to the template is an instance of one of the template type argu...

LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key

@ Mod

The access may modify the value stored in memory.

OutputIt move(R &&Range, OutputIt Out)

Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.

decltype(auto) cast(const From &Val)

cast - Return the argument parameter cast to the specified type.

LLVM_ABI bool isAllocationFn(const Value *V, const TargetLibraryInfo *TLI)

Tests if a value is a call or invoke to a library function that allocates or reallocates memory (eith...

AnalysisManager< Function > FunctionAnalysisManager

Convenience typedef for the Function analysis manager.

AllocTokenMode

Modes for generating allocation token IDs.

@ TypeHash

Token ID based on allocated type hash.

@ Random

Simple mode that returns a statically-assigned random token ID.

@ Increment

Incrementally increasing token ID.

@ TypeHashPointerSplit

Token ID based on allocated type hash, where the top half ID-space is reserved for types that contain...

LLVM_ABI std::optional< AllocTokenMode > getAllocTokenModeFromString(StringRef Name)

Returns the AllocTokenMode from its canonical string name; if an invalid name was provided returns nu...

AnalysisManager< Module > ModuleAnalysisManager

Convenience typedef for the Module analysis manager.

Implement std::hash so that hash_code can be used in STL containers.