//
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "stack-protector"
#include "llvm/CodeGen/StackProtector.h"
-#include "llvm/CodeGen/Analysis.h"
-#include "llvm/CodeGen/Passes.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/Statistic.h"
-#include "llvm/Analysis/Dominators.h"
+#include "llvm/Analysis/BranchProbabilityInfo.h"
#include "llvm/Analysis/ValueTracking.h"
+#include "llvm/CodeGen/Analysis.h"
+#include "llvm/CodeGen/Passes.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Target/TargetSubtargetInfo.h"
#include <cstdlib>
using namespace llvm;
+#define DEBUG_TYPE "stack-protector"
+
STATISTIC(NumFunProtected, "Number of functions protected");
STATISTIC(NumAddrTaken, "Number of local variables that have their address"
" taken.");
-static cl::opt<bool>
-EnableSelectionDAGSP("enable-selectiondag-sp", cl::init(true),
- cl::Hidden);
+static cl::opt<bool> EnableSelectionDAGSP("enable-selectiondag-sp",
+ cl::init(true), cl::Hidden);
char StackProtector::ID = 0;
-INITIALIZE_PASS(StackProtector, "stack-protector",
- "Insert stack protectors", false, true)
+INITIALIZE_PASS(StackProtector, "stack-protector", "Insert stack protectors",
+ false, true)
FunctionPass *llvm::createStackProtectorPass(const TargetMachine *TM) {
return new StackProtector(TM);
}
-StackProtector::SSPLayoutKind StackProtector::getSSPLayout(const AllocaInst *AI)
- const {
+StackProtector::SSPLayoutKind
+StackProtector::getSSPLayout(const AllocaInst *AI) const {
return AI ? Layout.lookup(AI) : SSPLK_None;
}
+void StackProtector::adjustForColoring(const AllocaInst *From,
+ const AllocaInst *To) {
+ // When coloring replaces one alloca with another, transfer the SSPLayoutKind
+ // tag from the remapped to the target alloca. The remapped alloca should
+ // have a size smaller than or equal to the replacement alloca.
+ SSPLayoutMap::iterator I = Layout.find(From);
+ if (I != Layout.end()) {
+ SSPLayoutKind Kind = I->second;
+ Layout.erase(I);
+
+ // Transfer the tag, but make sure that SSPLK_AddrOf does not overwrite
+ // SSPLK_SmallArray or SSPLK_LargeArray, and make sure that
+ // SSPLK_SmallArray does not overwrite SSPLK_LargeArray.
+ I = Layout.find(To);
+ if (I == Layout.end())
+ Layout.insert(std::make_pair(To, Kind));
+ else if (I->second != SSPLK_LargeArray && Kind != SSPLK_AddrOf)
+ I->second = Kind;
+ }
+}
+
bool StackProtector::runOnFunction(Function &Fn) {
F = &Fn;
M = F->getParent();
- DT = getAnalysisIfAvailable<DominatorTree>();
- TLI = TM->getTargetLowering();
+ DominatorTreeWrapperPass *DTWP =
+ getAnalysisIfAvailable<DominatorTreeWrapperPass>();
+ DT = DTWP ? &DTWP->getDomTree() : nullptr;
+ TLI = TM->getSubtargetImpl(Fn)->getTargetLowering();
- if (!RequiresStackProtector()) return false;
+ Attribute Attr = Fn.getFnAttribute("stack-protector-buffer-size");
+ if (Attr.isStringAttribute() &&
+ Attr.getValueAsString().getAsInteger(10, SSPBufferSize))
+ return false; // Invalid integer string
- Attribute Attr =
- Fn.getAttributes().getAttribute(AttributeSet::FunctionIndex,
- "stack-protector-buffer-size");
- if (Attr.isStringAttribute())
- Attr.getValueAsString().getAsInteger(10, SSPBufferSize);
+ if (!RequiresStackProtector())
+ return false;
++NumFunProtected;
return InsertStackProtectors();
/// it is "large" ( >= ssp-buffer-size). In the case of a structure with
/// multiple arrays, this gets set if any of them is large.
bool StackProtector::ContainsProtectableArray(Type *Ty, bool &IsLarge,
- bool Strong, bool InStruct)
- const {
- if (!Ty) return false;
+ bool Strong,
+ bool InStruct) const {
+ if (!Ty)
+ return false;
if (ArrayType *AT = dyn_cast<ArrayType>(Ty)) {
if (!AT->getElementType()->isIntegerTy(8)) {
// If we're on a non-Darwin platform or we're inside of a structure, don't
// If an array has more than SSPBufferSize bytes of allocated space, then we
// emit stack protectors.
- if (SSPBufferSize <= TLI->getDataLayout()->getTypeAllocSize(AT)) {
+ if (SSPBufferSize <= M->getDataLayout().getTypeAllocSize(AT)) {
IsLarge = true;
return true;
- }
+ }
if (Strong)
// Require a protector for all arrays in strong mode
}
const StructType *ST = dyn_cast<StructType>(Ty);
- if (!ST) return false;
+ if (!ST)
+ return false;
bool NeedsProtector = false;
for (StructType::element_iterator I = ST->element_begin(),
- E = ST->element_end(); I != E; ++I)
+ E = ST->element_end();
+ I != E; ++I)
if (ContainsProtectableArray(*I, IsLarge, Strong, true)) {
// If the element is a protectable array and is large (>= SSPBufferSize)
// then we are done. If the protectable array is not large, then
}
bool StackProtector::HasAddressTaken(const Instruction *AI) {
- for (Value::const_use_iterator UI = AI->use_begin(), UE = AI->use_end();
- UI != UE; ++UI) {
- const User *U = *UI;
+ for (const User *U : AI->users()) {
if (const StoreInst *SI = dyn_cast<StoreInst>(U)) {
if (AI == SI->getValueOperand())
return true;
} else if (const PHINode *PN = dyn_cast<PHINode>(U)) {
// Keep track of what PHI nodes we have already visited to ensure
// they are only visited once.
- if (VisitedPHIs.insert(PN))
+ if (VisitedPHIs.insert(PN).second)
if (HasAddressTaken(PN))
return true;
} else if (const GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(U)) {
bool StackProtector::RequiresStackProtector() {
bool Strong = false;
bool NeedsProtector = false;
- if (F->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
- Attribute::StackProtectReq)) {
+ if (F->hasFnAttribute(Attribute::StackProtectReq)) {
NeedsProtector = true;
Strong = true; // Use the same heuristic as strong to determine SSPLayout
- } else if (F->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
- Attribute::StackProtectStrong))
+ } else if (F->hasFnAttribute(Attribute::StackProtectStrong))
Strong = true;
- else if (!F->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
- Attribute::StackProtect))
+ else if (!F->hasFnAttribute(Attribute::StackProtect))
return false;
- for (Function::iterator I = F->begin(), E = F->end(); I != E; ++I) {
- BasicBlock *BB = I;
-
- for (BasicBlock::iterator
- II = BB->begin(), IE = BB->end(); II != IE; ++II) {
- if (AllocaInst *AI = dyn_cast<AllocaInst>(II)) {
+ for (const BasicBlock &BB : *F) {
+ for (const Instruction &I : BB) {
+ if (const AllocaInst *AI = dyn_cast<AllocaInst>(&I)) {
if (AI->isArrayAllocation()) {
// SSP-Strong: Enable protectors for any call to alloca, regardless
// of size.
if (Strong)
return true;
- if (const ConstantInt *CI =
- dyn_cast<ConstantInt>(AI->getArraySize())) {
+ if (const auto *CI = dyn_cast<ConstantInt>(AI->getArraySize())) {
if (CI->getLimitedValue(SSPBufferSize) >= SSPBufferSize) {
// A call to alloca with size >= SSPBufferSize requires
// stack protectors.
static bool InstructionWillNotHaveChain(const Instruction *I) {
return !I->mayHaveSideEffects() && !I->mayReadFromMemory() &&
- isSafeToSpeculativelyExecute(I);
+ isSafeToSpeculativelyExecute(I);
}
/// Identify if RI has a previous instruction in the "Tail Position" and return
const unsigned MaxSearch = 4;
bool NoInterposingChain = true;
- for (BasicBlock::reverse_iterator I = llvm::next(BB->rbegin()), E = BB->rend();
+ for (BasicBlock::reverse_iterator I = std::next(BB->rbegin()), E = BB->rend();
I != E && SearchCounter < MaxSearch; ++I) {
Instruction *Inst = &*I;
// If we did not find a call see if we have an instruction that may create
// an interposing chain.
- NoInterposingChain = NoInterposingChain && InstructionWillNotHaveChain(Inst);
+ NoInterposingChain =
+ NoInterposingChain && InstructionWillNotHaveChain(Inst);
// Increment max search.
SearchCounter++;
}
- return 0;
+ return nullptr;
}
/// Insert code into the entry block that stores the __stack_chk_guard
/// Returns true if the platform/triple supports the stackprotectorcreate pseudo
/// node.
static bool CreatePrologue(Function *F, Module *M, ReturnInst *RI,
- const TargetLoweringBase *TLI, const Triple &Trip,
+ const TargetLoweringBase *TLI, const Triple &TT,
AllocaInst *&AI, Value *&StackGuardVar) {
bool SupportsSelectionDAGSP = false;
PointerType *PtrTy = Type::getInt8PtrTy(RI->getContext());
unsigned AddressSpace, Offset;
if (TLI->getStackCookieLocation(AddressSpace, Offset)) {
Constant *OffsetVal =
- ConstantInt::get(Type::getInt32Ty(RI->getContext()), Offset);
+ ConstantInt::get(Type::getInt32Ty(RI->getContext()), Offset);
- StackGuardVar = ConstantExpr::getIntToPtr(OffsetVal,
- PointerType::get(PtrTy,
- AddressSpace));
- } else if (Trip.getOS() == llvm::Triple::OpenBSD) {
+ StackGuardVar =
+ ConstantExpr::getIntToPtr(OffsetVal, PointerType::get(PtrTy,
+ AddressSpace));
+ } else if (TT.isOSOpenBSD()) {
StackGuardVar = M->getOrInsertGlobal("__guard_local", PtrTy);
cast<GlobalValue>(StackGuardVar)
- ->setVisibility(GlobalValue::HiddenVisibility);
+ ->setVisibility(GlobalValue::HiddenVisibility);
} else {
SupportsSelectionDAGSP = true;
StackGuardVar = M->getOrInsertGlobal("__stack_chk_guard", PtrTy);
}
IRBuilder<> B(&F->getEntryBlock().front());
- AI = B.CreateAlloca(PtrTy, 0, "StackGuardSlot");
+ AI = B.CreateAlloca(PtrTy, nullptr, "StackGuardSlot");
LoadInst *LI = B.CreateLoad(StackGuardVar, "StackGuard");
- B.CreateCall2(Intrinsic::getDeclaration(M, Intrinsic::stackprotector), LI,
- AI);
+ B.CreateCall(Intrinsic::getDeclaration(M, Intrinsic::stackprotector),
+ {LI, AI});
return SupportsSelectionDAGSP;
}
bool StackProtector::InsertStackProtectors() {
bool HasPrologue = false;
bool SupportsSelectionDAGSP =
- EnableSelectionDAGSP && !TM->Options.EnableFastISel;
- AllocaInst *AI = 0; // Place on stack that stores the stack guard.
- Value *StackGuardVar = 0; // The stack guard variable.
+ EnableSelectionDAGSP && !TM->Options.EnableFastISel;
+ AllocaInst *AI = nullptr; // Place on stack that stores the stack guard.
+ Value *StackGuardVar = nullptr; // The stack guard variable.
- for (Function::iterator I = F->begin(), E = F->end(); I != E; ) {
+ for (Function::iterator I = F->begin(), E = F->end(); I != E;) {
BasicBlock *BB = I++;
ReturnInst *RI = dyn_cast<ReturnInst>(BB->getTerminator());
if (!RI)
if (!HasPrologue) {
HasPrologue = true;
- SupportsSelectionDAGSP &= CreatePrologue(F, M, RI, TLI, Trip, AI,
- StackGuardVar);
+ SupportsSelectionDAGSP &=
+ CreatePrologue(F, M, RI, TLI, Trip, AI, StackGuardVar);
}
if (SupportsSelectionDAGSP) {
// Since we have a potential tail call, insert the special stack check
// intrinsic.
- Instruction *InsertionPt = 0;
+ Instruction *InsertionPt = nullptr;
if (CallInst *CI = FindPotentialTailCall(BB, RI, TLI)) {
InsertionPt = CI;
} else {
InsertionPt = RI;
// At this point we know that BB has a return statement so it *DOES*
// have a terminator.
- assert(InsertionPt != 0 && "BB must have a terminator instruction at "
- "this point.");
+ assert(InsertionPt != nullptr &&
+ "BB must have a terminator instruction at this point.");
}
Function *Intrinsic =
- Intrinsic::getDeclaration(M, Intrinsic::stackprotectorcheck);
+ Intrinsic::getDeclaration(M, Intrinsic::stackprotectorcheck);
CallInst::Create(Intrinsic, StackGuardVar, "", InsertionPt);
-
} else {
// If we do not support SelectionDAG based tail calls, generate IR level
// tail calls.
LoadInst *LI1 = B.CreateLoad(StackGuardVar);
LoadInst *LI2 = B.CreateLoad(AI);
Value *Cmp = B.CreateICmpEQ(LI1, LI2);
- B.CreateCondBr(Cmp, NewBB, FailBB);
+ unsigned SuccessWeight =
+ BranchProbabilityInfo::getBranchWeightStackProtector(true);
+ unsigned FailureWeight =
+ BranchProbabilityInfo::getBranchWeightStackProtector(false);
+ MDNode *Weights = MDBuilder(F->getContext())
+ .createBranchWeights(SuccessWeight, FailureWeight);
+ B.CreateCondBr(Cmp, NewBB, FailBB, Weights);
}
}
- // Return if we didn't modify any basic blocks. I.e., there are no return
+ // Return if we didn't modify any basic blocks. i.e., there are no return
// statements in the function.
if (!HasPrologue)
return false;
LLVMContext &Context = F->getContext();
BasicBlock *FailBB = BasicBlock::Create(Context, "CallStackCheckFailBlk", F);
IRBuilder<> B(FailBB);
- if (Trip.getOS() == llvm::Triple::OpenBSD) {
- Constant *StackChkFail = M->getOrInsertFunction(
- "__stack_smash_handler", Type::getVoidTy(Context),
- Type::getInt8PtrTy(Context), NULL);
+ if (Trip.isOSOpenBSD()) {
+ Constant *StackChkFail =
+ M->getOrInsertFunction("__stack_smash_handler",
+ Type::getVoidTy(Context),
+ Type::getInt8PtrTy(Context), nullptr);
B.CreateCall(StackChkFail, B.CreateGlobalStringPtr(F->getName(), "SSH"));
} else {
- Constant *StackChkFail = M->getOrInsertFunction(
- "__stack_chk_fail", Type::getVoidTy(Context), NULL);
- B.CreateCall(StackChkFail);
+ Constant *StackChkFail =
+ M->getOrInsertFunction("__stack_chk_fail", Type::getVoidTy(Context),
+ nullptr);
+ B.CreateCall(StackChkFail, {});
}
B.CreateUnreachable();
return FailBB;