LLVM: lib/CodeGen/StackProtector.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

51#include

52#include

53

54using namespace llvm;

55

56#define DEBUG_TYPE "stack-protector"

57

58STATISTIC(NumFunProtected, "Number of functions protected");

59STATISTIC(NumAddrTaken, "Number of local variables that have their address"

60 " taken.");

61

66

67

68

69

70

71

72

75 bool &HasIRCheck);

76

77

78

80

82 return HasPrologue && !HasIRCheck && isa(BB.getTerminator());

83}

84

86 if (Layout.empty())

87 return;

88

91 continue;

92

94 if (!AI)

95 continue;

96

98 if (LI == Layout.end())

99 continue;

100

102 }

103}

104

107

109 Info.RequireStackProtector =

111 Info.SSPBufferSize = F.getFnAttributeAsParsedInteger(

112 "stack-protector-buffer-size", SSPLayoutInfo::DefaultSSPBufferSize);

114}

115

117

122 DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);

123

124 if (Info.RequireStackProtector)

126

127

128

129 if (F.hasPersonalityFn()) {

133 }

134

135 ++NumFunProtected;

137 Info.HasPrologue, Info.HasIRCheck);

138#ifdef EXPENSIVE_CHECKS

139 assert((!DT || DT->verify(DominatorTree::VerificationLevel::Full)) &&

140 "Failed to maintain validity of domtree!");

141#endif

142

143 if (!Changed)

148 return PA;

149}

150

152

155}

156

158 "Insert stack protectors", false, true)

163

165

169}

170

172 F = &Fn;

174 if (auto *DTWP = getAnalysisIfAvailable())

175 DTU.emplace(DTWP->getDomTree(), DomTreeUpdater::UpdateStrategy::Lazy);

176 TM = &getAnalysis().getTM<TargetMachine>();

177 LayoutInfo.HasPrologue = false;

178 LayoutInfo.HasIRCheck = false;

179

181 "stack-protector-buffer-size", SSPLayoutInfo::DefaultSSPBufferSize);

183 return false;

184

185

186

190 return false;

191 }

192

193 ++NumFunProtected;

194 bool Changed =

196 LayoutInfo.HasPrologue, LayoutInfo.HasIRCheck);

197#ifdef EXPENSIVE_CHECKS

199 DTU->getDomTree().verify(DominatorTree::VerificationLevel::Full)) &&

200 "Failed to maintain validity of domtree!");

201#endif

202 DTU.reset();

203 return Changed;

204}

205

206

207

208

210 bool &IsLarge, bool Strong,

211 bool InStruct) {

212 if (!Ty)

213 return false;

214 if (ArrayType *AT = dyn_cast(Ty)) {

215 if (!AT->getElementType()->isIntegerTy(8)) {

216

217

218

219

220 if (!Strong && (InStruct || Triple(M->getTargetTriple()).isOSDarwin()))

221 return false;

222 }

223

224

225

226 if (SSPBufferSize <= M->getDataLayout().getTypeAllocSize(AT)) {

227 IsLarge = true;

228 return true;

229 }

230

231 if (Strong)

232

233 return true;

234 }

235

236 const StructType *ST = dyn_cast(Ty);

237 if (!ST)

238 return false;

239

240 bool NeedsProtector = false;

241 for (Type *ET : ST->elements())

243

244

245

246 if (IsLarge)

247 return true;

248 NeedsProtector = true;

249 }

250

251 return NeedsProtector;

252}

253

254

259 for (const User *U : AI->users()) {

260 const auto *I = cast(U);

261

262

264 if (MemLoc && MemLoc->Size.hasValue() &&

266 return true;

267 switch (I->getOpcode()) {

268 case Instruction::Store:

269 if (AI == cast(I)->getValueOperand())

270 return true;

271 break;

272 case Instruction::AtomicCmpXchg:

273

274

275 if (AI == cast(I)->getNewValOperand())

276 return true;

277 break;

278 case Instruction::PtrToInt:

279 if (AI == cast(I)->getOperand(0))

280 return true;

281 break;

282 case Instruction::Call: {

283

284

285 const auto *CI = cast(I);

286 if (!CI->isDebugOrPseudoInst() && !CI->isLifetimeStartOrEnd())

287 return true;

288 break;

289 }

290 case Instruction::Invoke:

291 return true;

292 case Instruction::GetElementPtr: {

293

294

295

296

298 unsigned IndexSize = DL.getIndexTypeSizeInBits(I->getType());

300 if (GEP->accumulateConstantOffset(DL, Offset))

301 return true;

304 return true;

305

306

307

311 return true;

312 break;

313 }

314 case Instruction::BitCast:

315 case Instruction::Select:

316 case Instruction::AddrSpaceCast:

318 return true;

319 break;

320 case Instruction::PHI: {

321

322

323 const auto *PN = cast(I);

324 if (VisitedPHIs.insert(PN).second)

326 return true;

327 break;

328 }

329 case Instruction::Load:

330 case Instruction::AtomicRMW:

331 case Instruction::Ret:

332

333

334

335

336

337 break;

338 default:

339

340

341 return true;

342 }

343 }

344 return false;

345}

346

347

348

352 if (const auto *II = dyn_cast(&I))

353 if (II->getIntrinsicID() == Intrinsic::stackprotector)

354 return II;

355 return nullptr;

356}

357

358

359

360

361

362

363

364

365

366

367

368

369

370

373 Module *M = F->getParent();

374 bool Strong = false;

375 bool NeedsProtector = false;

376

377

378

379

381

382 unsigned SSPBufferSize = F->getFnAttributeAsParsedInteger(

383 "stack-protector-buffer-size", SSPLayoutInfo::DefaultSSPBufferSize);

384

385 if (F->hasFnAttribute(Attribute::SafeStack))

386 return false;

387

388

389

390

392

393 if (F->hasFnAttribute(Attribute::StackProtectReq)) {

394 if (!Layout)

395 return true;

396 ORE.emit([&]() {

398 << "Stack protection applied to function "

400 << " due to a function attribute or command-line switch";

401 });

402 NeedsProtector = true;

403 Strong = true;

404 } else if (F->hasFnAttribute(Attribute::StackProtectStrong))

405 Strong = true;

406 else if (F->hasFnAttribute(Attribute::StackProtect))

407 return false;

408

411 if (const AllocaInst *AI = dyn_cast(&I)) {

412 if (AI->isArrayAllocation()) {

413 auto RemarkBuilder = [&]() {

415 &I)

416 << "Stack protection applied to function "

418 << " due to a call to alloca or use of a variable length "

419 "array";

420 };

421 if (const auto *CI = dyn_cast(AI->getArraySize())) {

422 if (CI->getLimitedValue(SSPBufferSize) >= SSPBufferSize) {

423

424

425 if (!Layout)

426 return true;

429 ORE.emit(RemarkBuilder);

430 NeedsProtector = true;

431 } else if (Strong) {

432

433 if (!Layout)

434 return true;

437 ORE.emit(RemarkBuilder);

438 NeedsProtector = true;

439 }

440 } else {

441

442 if (!Layout)

443 return true;

446 ORE.emit(RemarkBuilder);

447 NeedsProtector = true;

448 }

449 continue;

450 }

451

452 bool IsLarge = false;

454 IsLarge, Strong, false)) {

455 if (!Layout)

456 return true;

457 Layout->insert(std::make_pair(

460 ORE.emit([&]() {

462 << "Stack protection applied to function "

464 << " due to a stack allocated buffer or struct containing a "

465 "buffer";

466 });

467 NeedsProtector = true;

468 continue;

469 }

470

471 if (Strong &&

473 AI, M->getDataLayout().getTypeAllocSize(AI->getAllocatedType()),

474 M, VisitedPHIs)) {

475 ++NumAddrTaken;

476 if (!Layout)

477 return true;

479 ORE.emit([&]() {

481 &I)

482 << "Stack protection applied to function "

484 << " due to the address of a local variable being taken";

485 });

486 NeedsProtector = true;

487 }

488

489

490 VisitedPHIs.clear();

491 }

492 }

493 }

494

495 return NeedsProtector;

496}

497

498

499

502 bool *SupportsSelectionDAGSP = nullptr) {

504 StringRef GuardMode = M->getStackProtectorGuard();

505 if ((GuardMode == "tls" || GuardMode.empty()) && Guard)

506 return B.CreateLoad(B.getPtrTy(), Guard, true, "StackGuard");

507

508

509

510

511

512

513

514

515

516

517

518

519 if (SupportsSelectionDAGSP)

520 *SupportsSelectionDAGSP = true;

522 return B.CreateIntrinsic(Intrinsic::stackguard, {}, {});

523}

524

525

526

527

528

529

530

531

532

533

534

537 bool SupportsSelectionDAGSP = false;

540 AI = B.CreateAlloca(PtrTy, nullptr, "StackGuardSlot");

541

543 B.CreateIntrinsic(Intrinsic::stackprotector, {}, {GuardSlot, AI});

544 return SupportsSelectionDAGSP;

545}

546

549 bool &HasIRCheck) {

550 auto *M = F->getParent();

551 auto *TLI = TM->getSubtargetImpl(*F)->getTargetLowering();

552

553

554

555

556 bool SupportsSelectionDAGSP =

557 TLI->useStackGuardXorFP() ||

559 AllocaInst *AI = nullptr;

561

563

564 if (&BB == FailBB)

565 continue;

566 Instruction *CheckLoc = dyn_cast(BB.getTerminator());

568 for (auto &Inst : BB)

569 if (auto *CB = dyn_cast(&Inst))

570

571

572 if (CB->doesNotReturn() && !CB->doesNotThrow()) {

573 CheckLoc = CB;

574 break;

575 }

576

577 if (!CheckLoc)

578 continue;

579

580

581 if (!HasPrologue) {

582 HasPrologue = true;

583 SupportsSelectionDAGSP &= CreatePrologue(F, M, CheckLoc, TLI, AI);

584 }

585

586

587

588 if (SupportsSelectionDAGSP)

589 break;

590

591

592

593 if (!AI) {

595 assert(SPCall && "Call to llvm.stackprotector is missing");

597 }

598

599

600

601

602 HasIRCheck = true;

603

604

605

606

607

608

610 if (Prev && isa(Prev) && cast(Prev)->isTailCall())

611 CheckLoc = Prev;

612 else if (Prev) {

614 if (Prev && isa(Prev) && cast(Prev)->isTailCall())

615 CheckLoc = Prev;

616 }

617

618

619

620

621 if (Function *GuardCheck = TLI->getSSPStackGuardCheck(*M)) {

622

623

625 LoadInst *Guard = B.CreateLoad(B.getPtrTy(), AI, true, "Guard");

626 CallInst *Call = B.CreateCall(GuardCheck, {Guard});

627 Call->setAttributes(GuardCheck->getAttributes());

628 Call->setCallingConv(GuardCheck->getCallingConv());

629 } else {

630

631

632

633

634

635

636

637

638

639

640

641

642

643

644

645

646

647

648

649

650

651

652

653

654

655

656

657

658

659 if (!FailBB)

661

664 LoadInst *LI2 = B.CreateLoad(B.getPtrTy(), AI, true);

665 auto *Cmp = cast(B.CreateICmpNE(Guard, LI2));

666 auto SuccessProb =

668 auto FailureProb =

672 SuccessProb.getNumerator());

673

675 false, Weights, DTU,

676 nullptr, FailBB);

677

678 auto *BI = cast(Cmp->getParent()->getTerminator());

679 BasicBlock *NewBB = BI->getSuccessor(1);

680 NewBB->setName("SP_return");

682

683 Cmp->setPredicate(Cmp->getInversePredicate());

684 BI->swapSuccessors();

685 }

686 }

687

688

689

690 return HasPrologue;

691}

692

694 auto *M = F->getParent();

698 if (F->getSubprogram())

699 B.SetCurrentDebugLocation(

704 StackChkFail = M->getOrInsertFunction("__stack_smash_handler",

707 Args.push_back(B.CreateGlobalString(F->getName(), "SSH"));

708 } else {

709 StackChkFail =

710 M->getOrInsertFunction("__stack_chk_fail", Type::getVoidTy(Context));

711 }

712 cast(StackChkFail.getCallee())->addFnAttr(Attribute::NoReturn);

713 B.CreateCall(StackChkFail, Args);

714 B.CreateUnreachable();

715 return FailBB;

716}

MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL

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

static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")

Analysis containing CSE Info

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

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

This file provides utility analysis objects describing memory locations.

uint64_t IntrinsicInst * II

FunctionAnalysisManager FAM

#define INITIALIZE_PASS_DEPENDENCY(depName)

#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)

#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)

assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())

This file defines the SmallPtrSet class.

This file defines the SmallVector class.

static bool HasAddressTaken(const Instruction *AI, TypeSize AllocSize, Module *M, SmallPtrSet< const PHINode *, 16 > &VisitedPHIs)

Check whether a stack allocation has its address taken.

static Value * getStackGuard(const TargetLoweringBase *TLI, Module *M, IRBuilder<> &B, bool *SupportsSelectionDAGSP=nullptr)

Create a stack guard loading and populate whether SelectionDAG SSP is supported.

static bool InsertStackProtectors(const TargetMachine *TM, Function *F, DomTreeUpdater *DTU, bool &HasPrologue, bool &HasIRCheck)

InsertStackProtectors - Insert code into the prologue and epilogue of the function.

static BasicBlock * CreateFailBB(Function *F, const Triple &Trip)

CreateFailBB - Create a basic block to jump to when the stack protector check fails.

static cl::opt< bool > DisableCheckNoReturn("disable-check-noreturn-call", cl::init(false), cl::Hidden)

static bool CreatePrologue(Function *F, Module *M, Instruction *CheckLoc, const TargetLoweringBase *TLI, AllocaInst *&AI)

Insert code into the entry block that stores the stack guard variable onto the stack:

static bool ContainsProtectableArray(Type *Ty, Module *M, unsigned SSPBufferSize, bool &IsLarge, bool Strong, bool InStruct)

static cl::opt< bool > EnableSelectionDAGSP("enable-selectiondag-sp", cl::init(true), cl::Hidden)

static const CallInst * findStackProtectorIntrinsic(Function &F)

Search for the first call to the llvm.stackprotector intrinsic and return it if present.

This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...

#define STATISTIC(VARNAME, DESC)

This file describes how to lower LLVM code to machine code.

Target-Independent Code Generator Pass Configuration Options pass.

Class for arbitrary precision integers.

an instruction to allocate memory on the stack

A container for analyses that lazily runs them and caches their results.

PassT::Result * getCachedResult(IRUnitT &IR) const

Get the cached result of an analysis pass for a given IR unit.

PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)

Get the result of an analysis pass for a given IR unit.

Represent the analysis usage information of a pass.

AnalysisUsage & addRequired()

AnalysisUsage & addPreserved()

Add the specified Pass class to the set of analyses preserved by this pass.

LLVM Basic Block Representation.

static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)

Creates a new BasicBlock.

void moveAfter(BasicBlock *MovePos)

Unlink this basic block from its current function and insert it right after MovePos in the function M...

const Instruction * getTerminator() const LLVM_READONLY

Returns the terminator instruction if the block is well formed or null if the block is not well forme...

static BranchProbability getBranchProbStackProtector(bool IsLikely)

Value * getArgOperand(unsigned i) const

This class represents a function call, abstracting a target machine's calling convention.

A parsed version of the target data layout string in and methods for querying it.

iterator find(const_arg_type_t< KeyT > Val)

std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)

Analysis pass which computes a DominatorTree.

bool verify(VerificationLevel VL=VerificationLevel::Full) const

verify - checks if the tree is correct.

Legacy analysis pass which computes a DominatorTree.

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

FunctionPass class - This class is used to implement most global optimizations.

uint64_t getFnAttributeAsParsedInteger(StringRef Kind, uint64_t Default=0) const

For a string attribute Kind, parse attribute as an integer.

bool hasPersonalityFn() const

Check whether this function has a personality function.

Constant * getPersonalityFn() const

Get the personality function associated with this function.

an instruction for type-safe pointer arithmetic to access elements of arrays and structs

Module * getParent()

Get the module that this global value is contained inside of...

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

const Instruction * getPrevNonDebugInstruction(bool SkipPseudoOp=false) const

Return a pointer to the previous non-debug instruction in the same basic block as 'this',...

This is an important class for using LLVM in a threaded context.

An instruction for reading from memory.

MDNode * createBranchWeights(uint32_t TrueWeight, uint32_t FalseWeight, bool IsExpected=false)

Return metadata containing two branch weights.

static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)

The MachineFrameInfo class represents an abstract stack frame until prolog/epilog code is inserted.

const AllocaInst * getObjectAllocation(int ObjectIdx) const

Return the underlying Alloca of the specified stack object if it exists.

@ SSPLK_SmallArray

Array or nested array < SSP-buffer-size.

@ SSPLK_LargeArray

Array or nested array >= SSP-buffer-size.

@ SSPLK_AddrOf

The address of this allocation is exposed and triggered protection.

void setObjectSSPLayout(int ObjectIdx, SSPLayoutKind Kind)

int getObjectIndexEnd() const

Return one past the maximum frame object index.

bool isDeadObjectIndex(int ObjectIdx) const

Returns true if the specified index corresponds to a dead object.

static std::optional< MemoryLocation > getOrNone(const Instruction *Inst)

A Module instance is used to store all the information related to an LLVM module.

static PassRegistry * getPassRegistry()

getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...

static PointerType * getUnqual(Type *ElementType)

This constructs a pointer to an object of the specified type in the default address space (address sp...

A set of analyses that are preserved following a run of a transformation pass.

static PreservedAnalyses all()

Construct a special preserved set that preserves all passes.

void preserve()

Mark an analysis as preserved.

static bool requiresStackProtector(Function *F, SSPLayoutMap *Layout=nullptr)

Check whether or not F needs a stack protector based upon the stack protector level.

Result run(Function &F, FunctionAnalysisManager &FAM)

void copyToMachineFrameInfo(MachineFrameInfo &MFI) const

bool shouldEmitSDCheck(const BasicBlock &BB) const

std::pair< iterator, bool > insert(PtrType Ptr)

Inserts Ptr if and only if there is no element in the container equal to Ptr.

SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.

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

PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM)

void getAnalysisUsage(AnalysisUsage &AU) const override

getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...

static bool requiresStackProtector(Function *F, SSPLayoutMap *Layout=nullptr)

Check whether or not F needs a stack protector based upon the stack protector level.

bool runOnFunction(Function &Fn) override

runOnFunction - Virtual method overriden by subclasses to do the per-function processing of the pass.

StringRef - Represent a constant reference to a string, i.e.

constexpr bool empty() const

empty - Check if the string is empty.

Class to represent struct types.

This base class for TargetLowering contains the SelectionDAG-independent parts that can be used from ...

virtual Value * getIRStackGuard(IRBuilderBase &IRB) const

If the target has a standard location for the stack protector guard, returns the address of that loca...

virtual void insertSSPDeclarations(Module &M) const

Inserts necessary declarations for SSP (stack protection) purpose.

Primary interface to the complete machine description for the target machine.

Target-Independent Code Generator Pass Configuration Options.

Triple - Helper class for working with autoconf configuration names.

bool isOSDarwin() const

Is this a "Darwin" OS (macOS, iOS, tvOS, watchOS, XROS, or DriverKit).

static constexpr TypeSize getFixed(ScalarTy ExactSize)

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

static Type * getVoidTy(LLVMContext &C)

LLVM Value Representation.

void setName(const Twine &Name)

Change the name of the value.

iterator_range< user_iterator > users()

LLVMContext & getContext() const

All values hold a context through their type.

constexpr ScalarTy getKnownMinValue() const

Returns the minimum value this quantity can represent.

static constexpr bool isKnownGT(const FixedOrScalableQuantity &LHS, const FixedOrScalableQuantity &RHS)

static constexpr bool isKnownGE(const FixedOrScalableQuantity &LHS, const FixedOrScalableQuantity &RHS)

initializer< Ty > init(const Ty &Val)

DiagnosticInfoOptimizationBase::Argument NV

This is an optimization pass for GlobalISel generic memory operations.

iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)

Make a range that does early increment to allow mutation of the underlying range without disrupting i...

FunctionPass * createStackProtectorPass()

createStackProtectorPass - This pass adds stack protectors to functions.

void initializeStackProtectorPass(PassRegistry &)

EHPersonality classifyEHPersonality(const Value *Pers)

See if the given exception handling personality function is one that we understand.

bool isFuncletEHPersonality(EHPersonality Pers)

Returns true if this is a personality function that invokes handler funclets (which must return to it...

Instruction * SplitBlockAndInsertIfThen(Value *Cond, BasicBlock::iterator SplitBefore, bool Unreachable, MDNode *BranchWeights=nullptr, DomTreeUpdater *DTU=nullptr, LoopInfo *LI=nullptr, BasicBlock *ThenBlock=nullptr)

Split the containing block at the specified instruction - everything before SplitBefore stays in the ...

A special type used by analysis passes to provide an address that identifies that particular analysis...