Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 55 additions & 27 deletions llvm/lib/CodeGen/StackProtector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,15 @@ static cl::opt<bool> DisableCheckNoReturn("disable-check-noreturn-call",
/// - The prologue code loads and stores the stack guard onto the stack.
/// - The epilogue checks the value stored in the prologue against the original
/// value. It calls __stack_chk_fail if they differ.
static bool InsertStackProtectors(const TargetMachine *TM, Function *F,
DomTreeUpdater *DTU, bool &HasPrologue,
bool &HasIRCheck);
static bool InsertStackProtectors(const TargetLowering &TLI,
const LibcallLoweringInfo &Libcalls,
Function *F, DomTreeUpdater *DTU,
bool &HasPrologue, bool &HasIRCheck);

/// CreateFailBB - Create a basic block to jump to when the stack protector
/// check fails.
static BasicBlock *CreateFailBB(Function *F, const TargetLowering &TLI);
static BasicBlock *CreateFailBB(Function *F,
const LibcallLoweringInfo &Libcalls);

bool SSPLayoutInfo::shouldEmitSDCheck(const BasicBlock &BB) const {
return HasPrologue && !HasIRCheck && isa<ReturnInst>(BB.getTerminator());
Expand Down Expand Up @@ -131,8 +133,23 @@ PreservedAnalyses StackProtectorPass::run(Function &F,
return PreservedAnalyses::all();
}

auto &MAMProxy = FAM.getResult<ModuleAnalysisManagerFunctionProxy>(F);
const LibcallLoweringModuleAnalysisResult *LibcallLowering =
MAMProxy.getCachedResult<LibcallLoweringModuleAnalysis>(*F.getParent());

if (!LibcallLowering) {
F.getContext().emitError("'" + LibcallLoweringModuleAnalysis::name() +
"' analysis required");
return PreservedAnalyses::all();
}

const TargetSubtargetInfo *STI = TM->getSubtargetImpl(F);
const TargetLowering *TLI = STI->getTargetLowering();
const LibcallLoweringInfo &Libcalls =
LibcallLowering->getLibcallLowering(*STI);

++NumFunProtected;
bool Changed = InsertStackProtectors(TM, &F, DT ? &DTU : nullptr,
bool Changed = InsertStackProtectors(*TLI, Libcalls, &F, DT ? &DTU : nullptr,
Info.HasPrologue, Info.HasIRCheck);
#ifdef EXPENSIVE_CHECKS
assert((!DT ||
Expand All @@ -156,6 +173,7 @@ StackProtector::StackProtector() : FunctionPass(ID) {

INITIALIZE_PASS_BEGIN(StackProtector, DEBUG_TYPE,
"Insert stack protectors", false, true)
INITIALIZE_PASS_DEPENDENCY(LibcallLoweringInfoWrapper)
INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
INITIALIZE_PASS_END(StackProtector, DEBUG_TYPE,
Expand All @@ -164,6 +182,7 @@ INITIALIZE_PASS_END(StackProtector, DEBUG_TYPE,
FunctionPass *llvm::createStackProtectorPass() { return new StackProtector(); }

void StackProtector::getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<LibcallLoweringInfoWrapper>();
AU.addRequired<TargetPassConfig>();
AU.addPreserved<DominatorTreeWrapperPass>();
}
Expand All @@ -190,9 +209,16 @@ bool StackProtector::runOnFunction(Function &Fn) {
return false;
}

const TargetSubtargetInfo *Subtarget = TM->getSubtargetImpl(Fn);
const LibcallLoweringInfo &Libcalls =
getAnalysis<LibcallLoweringInfoWrapper>().getLibcallLowering(*M,
*Subtarget);

const TargetLowering *TLI = Subtarget->getTargetLowering();

++NumFunProtected;
bool Changed =
InsertStackProtectors(TM, F, DTU ? &*DTU : nullptr,
InsertStackProtectors(*TLI, Libcalls, F, DTU ? &*DTU : nullptr,
LayoutInfo.HasPrologue, LayoutInfo.HasIRCheck);
#ifdef EXPENSIVE_CHECKS
assert((!DTU ||
Expand Down Expand Up @@ -519,10 +545,10 @@ bool SSPLayoutAnalysis::requiresStackProtector(Function *F,

/// Create a stack guard loading and populate whether SelectionDAG SSP is
/// supported.
static Value *getStackGuard(const TargetLoweringBase *TLI, Module *M,
static Value *getStackGuard(const TargetLoweringBase &TLI, Module *M,
IRBuilder<> &B,
bool *SupportsSelectionDAGSP = nullptr) {
Value *Guard = TLI->getIRStackGuard(B);
Value *Guard = TLI.getIRStackGuard(B);
StringRef GuardMode = M->getStackProtectorGuard();
if ((GuardMode == "tls" || GuardMode.empty()) && Guard)
return B.CreateLoad(B.getPtrTy(), Guard, true, "StackGuard");
Expand All @@ -540,7 +566,7 @@ static Value *getStackGuard(const TargetLoweringBase *TLI, Module *M,
// actually conveys the same information getIRStackGuard() already gives.
if (SupportsSelectionDAGSP)
*SupportsSelectionDAGSP = true;
TLI->insertSSPDeclarations(*M);
TLI.insertSSPDeclarations(*M);
return B.CreateIntrinsic(Intrinsic::stackguard, {});
}

Expand All @@ -561,23 +587,23 @@ static bool CreatePrologue(Function *F, Module *M, Instruction *CheckLoc,
PointerType *PtrTy = PointerType::getUnqual(CheckLoc->getContext());
AI = B.CreateAlloca(PtrTy, nullptr, "StackGuardSlot");

Value *GuardSlot = getStackGuard(TLI, M, B, &SupportsSelectionDAGSP);
Value *GuardSlot = getStackGuard(*TLI, M, B, &SupportsSelectionDAGSP);
B.CreateIntrinsic(Intrinsic::stackprotector, {GuardSlot, AI});
return SupportsSelectionDAGSP;
}

bool InsertStackProtectors(const TargetMachine *TM, Function *F,
bool InsertStackProtectors(const TargetLowering &TLI,
const LibcallLoweringInfo &Libcalls, Function *F,
DomTreeUpdater *DTU, bool &HasPrologue,
bool &HasIRCheck) {
auto *M = F->getParent();
auto *TLI = TM->getSubtargetImpl(*F)->getTargetLowering();

// If the target wants to XOR the frame pointer into the guard value, it's
// impossible to emit the check in IR, so the target *must* support stack
// protection in SDAG.
bool SupportsSelectionDAGSP =
TLI->useStackGuardXorFP() ||
(EnableSelectionDAGSP && !TM->Options.EnableFastISel);
TLI.useStackGuardXorFP() ||
(EnableSelectionDAGSP && !TLI.getTargetMachine().Options.EnableFastISel);
AllocaInst *AI = nullptr; // Place on stack that stores the stack guard.
BasicBlock *FailBB = nullptr;

Expand Down Expand Up @@ -610,7 +636,7 @@ bool InsertStackProtectors(const TargetMachine *TM, Function *F,
// Generate prologue instrumentation if not already generated.
if (!HasPrologue) {
HasPrologue = true;
SupportsSelectionDAGSP &= CreatePrologue(F, M, CheckLoc, TLI, AI);
SupportsSelectionDAGSP &= CreatePrologue(F, M, CheckLoc, &TLI, AI);
}

// SelectionDAG based code generation. Nothing else needs to be done here.
Expand All @@ -635,13 +661,13 @@ bool InsertStackProtectors(const TargetMachine *TM, Function *F,
// inserted before the call rather than between it and the return.
Instruction *Prev = CheckLoc->getPrevNode();
if (auto *CI = dyn_cast_if_present<CallInst>(Prev))
if (CI->isTailCall() && isInTailCallPosition(*CI, *TM))
if (CI->isTailCall() && isInTailCallPosition(*CI, TLI.getTargetMachine()))
CheckLoc = Prev;

// Generate epilogue instrumentation. The epilogue intrumentation can be
// function-based or inlined depending on which mechanism the target is
// providing.
if (Function *GuardCheck = TLI->getSSPStackGuardCheck(*M)) {
if (Function *GuardCheck = TLI.getSSPStackGuardCheck(*M)) {
// Generate the function-based epilogue instrumentation.
// The target provides a guard check function, generate a call to it.
IRBuilder<> B(CheckLoc);
Expand Down Expand Up @@ -680,7 +706,7 @@ bool InsertStackProtectors(const TargetMachine *TM, Function *F,
// merge pass will merge together all of the various BB into one including
// fail BB generated by the stack protector pseudo instruction.
if (!FailBB)
FailBB = CreateFailBB(F, *TLI);
FailBB = CreateFailBB(F, Libcalls);

IRBuilder<> B(CheckLoc);
Value *Guard = getStackGuard(TLI, M, B);
Expand Down Expand Up @@ -713,7 +739,7 @@ bool InsertStackProtectors(const TargetMachine *TM, Function *F,
return HasPrologue;
}

BasicBlock *CreateFailBB(Function *F, const TargetLowering &TLI) {
BasicBlock *CreateFailBB(Function *F, const LibcallLoweringInfo &Libcalls) {
auto *M = F->getParent();
LLVMContext &Context = F->getContext();
BasicBlock *FailBB = BasicBlock::Create(Context, "CallStackCheckFailBlk", F);
Expand All @@ -724,14 +750,16 @@ BasicBlock *CreateFailBB(Function *F, const TargetLowering &TLI) {
FunctionCallee StackChkFail;
SmallVector<Value *, 1> Args;

if (const char *ChkFailName =
TLI.getLibcallName(RTLIB::STACKPROTECTOR_CHECK_FAIL)) {
StackChkFail =
M->getOrInsertFunction(ChkFailName, Type::getVoidTy(Context));
} else if (const char *SSHName =
TLI.getLibcallName(RTLIB::STACK_SMASH_HANDLER)) {
StackChkFail = M->getOrInsertFunction(SSHName, Type::getVoidTy(Context),
PointerType::getUnqual(Context));
if (RTLIB::LibcallImpl ChkFailImpl =
Libcalls.getLibcallImpl(RTLIB::STACKPROTECTOR_CHECK_FAIL)) {
StackChkFail = M->getOrInsertFunction(
RTLIB::RuntimeLibcallsInfo::getLibcallImplName(ChkFailImpl),
Type::getVoidTy(Context));
} else if (RTLIB::LibcallImpl SSHImpl =
Libcalls.getLibcallImpl(RTLIB::STACK_SMASH_HANDLER)) {
StackChkFail = M->getOrInsertFunction(
RTLIB::RuntimeLibcallsInfo::getLibcallImplName(SSHImpl),
Type::getVoidTy(Context), PointerType::getUnqual(Context));
Args.push_back(B.CreateGlobalString(F->getName(), "SSH"));
} else {
Context.emitError("no libcall available for stack protector");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
; RUN: not opt -disable-output -mtriple=nvptx64-- -enable-selectiondag-sp=0 -passes=stack-protector %s 2>&1 | FileCheck %s
; RUN: not opt -disable-output -mtriple=nvptx64-- -enable-selectiondag-sp=0 -passes='require<libcall-lowering-info>,stack-protector' %s 2>&1 | FileCheck %s

; CHECK: error: no libcall available for stack protector
define void @func() sspreq nounwind {
Expand Down
4 changes: 2 additions & 2 deletions llvm/test/CodeGen/X86/stack-protector-atomicrmw-xchg.ll
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt -S -mtriple=x86_64-unknown-linux-gnu -passes=stack-protector < %s | FileCheck %s
; RUN: opt -S -mtriple=x86_64-unknown-linux-gnu -passes='require<domtree>,stack-protector' < %s | FileCheck %s
; RUN: opt -S -mtriple=x86_64-unknown-linux-gnu -passes='require<libcall-lowering-info>,stack-protector' < %s | FileCheck %s
; RUN: opt -S -mtriple=x86_64-unknown-linux-gnu -passes='require<libcall-lowering-info>,function(require<domtree>,stack-protector)' < %s | FileCheck %s

define void @atomicrmw_xchg(ptr %p) sspstrong {
; CHECK-LABEL: define void @atomicrmw_xchg(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
;; This is a minimal reproducer that caused StackProtector to crash with a bad cast when
;; CrossDSOCFI is used. This test just needs to not crash.
; REQUIRES: x86-registered-target
; RUN: opt -mtriple=x86_64-pc-linux-gnu %s -passes=lowertypetests,cross-dso-cfi,stack-protector
; RUN: opt -mtriple=x86_64-pc-linux-gnu %s -passes='require<libcall-lowering-info>,lowertypetests,cross-dso-cfi,stack-protector'

define hidden void @__stack_chk_fail() !type !1{
unreachable
Expand Down
7 changes: 7 additions & 0 deletions llvm/test/Transforms/StackProtector/missing-analysis.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
; REQUIRES: x86-registered-target
; RUN: not opt -mtriple=x86_64-- -passes=expand-fp -disable-output %s 2>&1 | FileCheck %s

; CHECK: 'LibcallLoweringModuleAnalysis' analysis required
define void @empty() {
ret void
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
;; __stack_chk_fail should have the noreturn attr even if it is an alias
; REQUIRES: x86-registered-target
; RUN: opt -mtriple=x86_64-pc-linux-gnu %s -passes=stack-protector -S | FileCheck %s
; RUN: opt -mtriple=x86_64-pc-linux-gnu %s -passes='require<libcall-lowering-info>,stack-protector' -S | FileCheck %s

define hidden void @__stack_chk_fail_impl() {
unreachable
Expand Down
Loading