76 #define DEBUG_TYPE "safe-stack" 80 STATISTIC(NumFunctions,
"Total number of functions");
81 STATISTIC(NumUnsafeStackFunctions,
"Number of functions with unsafe stack");
82 STATISTIC(NumUnsafeStackRestorePointsFunctions,
83 "Number of functions that use setjmp or exceptions");
85 STATISTIC(NumAllocas,
"Total number of allocas");
86 STATISTIC(NumUnsafeStaticAllocas,
"Number of unsafe static allocas");
87 STATISTIC(NumUnsafeDynamicAllocas,
"Number of unsafe dynamic allocas");
88 STATISTIC(NumUnsafeByValArguments,
"Number of unsafe byval arguments");
89 STATISTIC(NumUnsafeStackRestorePoints,
"Number of setjmps and landingpads");
107 const Value *AllocaPtr;
136 Value *UnsafeStackPtr =
nullptr;
144 enum { StackAlignment = 16 };
164 uint64_t getStaticAllocaAllocationSize(
const AllocaInst* AI);
187 Value *StaticTop,
bool NeedDynamicTop);
192 void moveDynamicAllocasToUnsafeStack(
Function &F,
Value *UnsafeStackPtr,
196 bool IsSafeStackAlloca(
const Value *AllocaPtr, uint64_t AllocaSize);
199 const Value *AllocaPtr, uint64_t AllocaSize);
200 bool IsAccessSafe(
Value *Addr, uint64_t
Size,
const Value *AllocaPtr,
201 uint64_t AllocaSize);
203 bool ShouldInlinePointerAddress(
CallSite &CS);
204 void TryInlinePointerAddress();
209 :
F(F), TL(TL), DL(DL), SE(SE),
220 uint64_t SafeStack::getStaticAllocaAllocationSize(
const AllocaInst* AI) {
226 Size *=
C->getZExtValue();
231 bool SafeStack::IsAccessSafe(
Value *Addr, uint64_t AccessSize,
232 const Value *AllocaPtr, uint64_t AllocaSize) {
233 AllocaOffsetRewriter
Rewriter(SE, AllocaPtr);
234 const SCEV *Expr = Rewriter.visit(SE.getSCEV(Addr));
236 uint64_t BitWidth = SE.getTypeSizeInBits(Expr->
getType());
243 bool Safe = AllocaRange.
contains(AccessRange);
246 dbgs() <<
"[SafeStack] " 247 << (isa<AllocaInst>(AllocaPtr) ?
"Alloca " :
"ByValArgument ")
248 << *AllocaPtr <<
"\n" 249 <<
" Access " << *Addr <<
"\n" 251 <<
" U: " << SE.getUnsignedRange(Expr)
252 <<
", S: " << SE.getSignedRange(Expr) <<
"\n" 253 <<
" Range " << AccessRange <<
"\n" 254 <<
" AllocaRange " << AllocaRange <<
"\n" 255 <<
" " << (Safe ?
"safe" :
"unsafe") <<
"\n");
261 const Value *AllocaPtr,
262 uint64_t AllocaSize) {
263 if (
auto MTI = dyn_cast<MemTransferInst>(MI)) {
264 if (MTI->getRawSource() != U && MTI->getRawDest() != U)
273 if (!Len)
return false;
274 return IsAccessSafe(U, Len->getZExtValue(), AllocaPtr, AllocaSize);
280 bool SafeStack::IsSafeStackAlloca(
const Value *AllocaPtr, uint64_t AllocaSize) {
289 while (!WorkList.
empty()) {
291 for (
const Use &UI : V->
uses()) {
292 auto I = cast<const Instruction>(UI.getUser());
295 switch (
I->getOpcode()) {
297 if (!IsAccessSafe(UI, DL.getTypeStoreSize(
I->getType()), AllocaPtr,
302 case Instruction::VAArg:
306 if (V ==
I->getOperand(0)) {
309 <<
"[SafeStack] Unsafe alloca: " << *AllocaPtr
310 <<
"\n store of address: " << *
I <<
"\n");
314 if (!IsAccessSafe(UI, DL.getTypeStoreSize(
I->getOperand(0)->getType()),
315 AllocaPtr, AllocaSize))
324 case Instruction::Invoke: {
327 if (
I->isLifetimeStartOrEnd())
331 if (!IsMemIntrinsicSafe(MI, UI, AllocaPtr, AllocaSize)) {
333 <<
"[SafeStack] Unsafe alloca: " << *AllocaPtr
334 <<
"\n unsafe memintrinsic: " << *
I <<
"\n");
353 <<
"\n unsafe call: " << *
I <<
"\n");
361 WorkList.
push_back(cast<const Instruction>(
I));
371 Value *StackGuardVar = TL.getIRStackGuard(IRB);
375 return IRB.
CreateLoad(StackGuardVar,
"StackGuard");
378 void SafeStack::findInsts(
Function &F,
385 if (
auto AI = dyn_cast<AllocaInst>(&
I)) {
388 uint64_t
Size = getStaticAllocaAllocationSize(AI);
389 if (IsSafeStackAlloca(AI, Size))
393 ++NumUnsafeStaticAllocas;
396 ++NumUnsafeDynamicAllocas;
399 }
else if (
auto RI = dyn_cast<ReturnInst>(&
I)) {
401 }
else if (
auto CI = dyn_cast<CallInst>(&
I)) {
403 if (CI->getCalledFunction() && CI->canReturnTwice())
405 }
else if (
auto LP = dyn_cast<LandingPadInst>(&
I)) {
408 }
else if (
auto II = dyn_cast<IntrinsicInst>(&
I)) {
411 "gcroot intrinsic not compatible with safestack attribute");
415 if (!
Arg.hasByValAttr())
419 if (IsSafeStackAlloca(&
Arg, Size))
422 ++NumUnsafeByValArguments;
430 Value *StaticTop,
bool NeedDynamicTop) {
431 assert(StaticTop &&
"The stack top isn't set.");
433 if (StackRestorePoints.
empty())
443 if (NeedDynamicTop) {
447 "unsafe_stack_dynamic_ptr");
453 ++NumUnsafeStackRestorePoints;
456 Value *CurrentTop = DynamicTop ? IRB.
CreateLoad(DynamicTop) : StaticTop;
471 .createBranchWeights(SuccessProb.getNumerator(),
472 FailureProb.getNumerator());
486 Value *SafeStack::moveStaticAllocasToUnsafeStack(
490 if (StaticAllocas.
empty() && ByValArguments.
empty())
497 SSC.removeAllMarkers();
501 if (StackGuardSlot) {
505 SSL.
addObject(StackGuardSlot, getStaticAllocaAllocationSize(StackGuardSlot),
506 Align, SSC.getFullLiveRange());
511 uint64_t
Size = DL.getTypeStoreSize(Ty);
516 unsigned Align =
std::max((
unsigned)DL.getPrefTypeAlignment(Ty),
517 Arg->getParamAlignment());
518 SSL.
addObject(
Arg, Size, Align, SSC.getFullLiveRange());
523 uint64_t
Size = getStaticAllocaAllocationSize(AI);
531 SSL.
addObject(AI, Size, Align, SSC.getLiveRange(AI));
539 if (FrameAlignment > StackAlignment) {
551 if (StackGuardSlot) {
568 uint64_t
Size = DL.getTypeStoreSize(Ty);
590 uint64_t
Size = getStaticAllocaAllocationSize(AI);
600 std::string
Name = std::string(AI->
getName()) +
".unsafe";
606 if (
auto *PHI = dyn_cast<PHINode>(User))
607 InsertBefore = PHI->getIncomingBlock(U)->getTerminator();
616 if (
auto *PHI = dyn_cast<PHINode>(User)) {
619 auto *BB = PHI->getIncomingBlock(U);
620 for (
unsigned I = 0;
I < PHI->getNumIncomingValues(); ++
I)
621 if (PHI->getIncomingBlock(
I) == BB)
622 PHI->setIncomingValue(
I, Replacement);
641 "unsafe_stack_static_top");
646 void SafeStack::moveDynamicAllocasToUnsafeStack(
656 if (ArraySize->
getType() != IntPtrTy)
660 uint64_t TySize = DL.getTypeAllocSize(Ty);
669 (
unsigned)StackAlignment);
682 if (AI->
hasName() && isa<Instruction>(NewAI))
691 if (!DynamicAllocas.empty()) {
703 II->replaceAllUsesWith(LI);
704 II->eraseFromParent();
710 II->eraseFromParent();
716 bool SafeStack::ShouldInlinePointerAddress(
CallSite &CS) {
726 void SafeStack::TryInlinePointerAddress() {
727 if (!isa<CallInst>(UnsafeStackPtr))
738 if (!ShouldInlinePointerAddress(CS))
745 bool SafeStack::run() {
747 "Can't run SafeStack on a function without the attribute");
766 findInsts(F, StaticAllocas, DynamicAllocas, ByValArguments, Returns,
769 if (StaticAllocas.
empty() && DynamicAllocas.
empty() &&
770 ByValArguments.
empty() && StackRestorePoints.
empty())
773 if (!StaticAllocas.
empty() || !DynamicAllocas.
empty() ||
774 !ByValArguments.
empty())
775 ++NumUnsafeStackFunctions;
777 if (!StackRestorePoints.
empty())
778 ++NumUnsafeStackRestorePointsFunctions;
785 if (SafeStackUsePointerAddress) {
787 "__safestack_pointer_address", StackPtrTy->getPointerTo(0));
790 UnsafeStackPtr = TL.getSafeStackPointerLocation(IRB);
796 IRB.
CreateLoad(UnsafeStackPtr,
false,
"unsafe_stack_ptr");
810 checkStackGuard(IRBRet, F, *RI, StackGuardSlot, StackGuard);
817 moveStaticAllocasToUnsafeStack(IRB, F, StaticAllocas, ByValArguments,
818 Returns, BasePointer, StackGuardSlot);
826 AllocaInst *DynamicTop = createStackRestorePoints(
827 IRB, F, StackRestorePoints, StaticTop, !DynamicAllocas.
empty());
830 moveDynamicAllocasToUnsafeStack(F, UnsafeStackPtr, DynamicTop,
839 TryInlinePointerAddress();
866 " for this function\n");
872 " is not available\n");
876 TM = &getAnalysis<TargetPassConfig>().getTM<TargetMachine>();
882 auto &TLI = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
883 auto &ACT = getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
896 return SafeStack(F, *TL, *DL, SE).run();
905 "Safe Stack instrumentation pass",
false,
false)
Return a value (possibly void), from a function.
User::const_op_iterator arg_iterator
The type of iterator to use when looping over actual arguments at this call site. ...
SymbolTableList< Instruction >::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
A parsed version of the target data layout string in and methods for querying it. ...
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
Safe Stack instrumentation pass
iterator_range< use_iterator > uses()
DILocation * get() const
Get the underlying DILocation.
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
void addObject(const Value *V, unsigned Size, unsigned Alignment, const StackColoring::LiveRange &Range)
Add an object to the stack frame.
GCNRegPressure max(const GCNRegPressure &P1, const GCNRegPressure &P2)
This class represents an incoming formal argument to a Function.
AllocaInst * CreateAlloca(Type *Ty, unsigned AddrSpace, Value *ArraySize=nullptr, const Twine &Name="")
void replaceDbgValueForAlloca(AllocaInst *AI, Value *NewAllocaAddress, DIBuilder &Builder, int Offset=0)
Replaces multiple llvm.dbg.value instructions when the alloca it describes is replaced with a new val...
bool replaceDbgDeclareForAlloca(AllocaInst *AI, Value *NewAllocaAddress, DIBuilder &Builder, bool DerefBefore, int Offset, bool DerefAfter)
Replaces llvm.dbg.declare instruction when the alloca it describes is replaced with a new value...
Value * CreateICmpNE(Value *LHS, Value *RHS, const Twine &Name="")
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
This class represents lattice values for constants.
Constant * getOrInsertFunction(StringRef Name, FunctionType *T, AttributeList AttributeList)
Look up the specified function in the module symbol table.
LoadInst * CreateLoad(Type *Ty, Value *Ptr, const char *Name)
Provided to resolve 'CreateLoad(Ty, Ptr, "...")' correctly, instead of converting the string to 'bool...
unsigned getFrameSize()
Returns the size of the entire frame.
Compute live ranges of allocas.
void push_back(const T &Elt)
The main scalar evolution driver.
An immutable pass that tracks lazily created AssumptionCache objects.
virtual const TargetLowering * getTargetLowering() const
bool isInterposable() const
Return true if this global's definition can be substituted with an arbitrary definition at link time...
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
STATISTIC(NumFunctions, "Total number of functions")
uint64_t alignTo(uint64_t Value, uint64_t Align, uint64_t Skew=0)
Returns the next integer (mod 2**64) that is greater than or equal to Value and is a multiple of Alig...
InlineResult InlineFunction(CallInst *C, InlineFunctionInfo &IFI, AAResults *CalleeAAR=nullptr, bool InsertLifetime=true)
This function inlines the called function into the basic block of the caller.
This defines the Use class.
This class captures the data input to the InlineFunction call, and records the auxiliary results prod...
Value * getLength() const
INITIALIZE_PASS_BEGIN(SafeStackLegacyPass, DEBUG_TYPE, "Safe Stack instrumentation pass", false, false) INITIALIZE_PASS_END(SafeStackLegacyPass
bool isNoInline() const
Return true if the call should not be inlined.
static cl::opt< bool > SafeStackUsePointerAddress("safestack-use-pointer-address", cl::init(false), cl::Hidden)
Use __safestack_pointer_address even if the platform has a faster way of access safe stack pointer...
const SCEV * getZero(Type *Ty)
Return a SCEV for the constant 0 of a specific type.
AnalysisUsage & addRequired()
#define INITIALIZE_PASS_DEPENDENCY(depName)
amdgpu Simplify well known AMD library false Value Value const Twine & Name
inst_iterator inst_begin(Function *F)
unsigned getObjectOffset(const Value *V)
Returns the offset to the object start in the stack frame.
Type * getPointerElementType() const
const DataLayout & getDataLayout() const
Get the data layout for the module's target platform.
unsigned getAlignment() const
Return the alignment of the memory that is being allocated by the instruction.
PointerType * getType() const
Overload to return most specific pointer type.
A Use represents the edge between a Value definition and its users.
bool isInlineViable(Function &Callee)
Minimal filter to detect invalid constructs for inlining.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
FunctionPass * createSafeStackPass()
This pass splits the stack into a safe stack and an unsafe stack to protect against stack-based overf...
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
This file contains the simple types necessary to represent the attributes associated with functions a...
bool contains(const APInt &Val) const
Return true if the specified value is in the set.
Target-Independent Code Generator Pass Configuration Options.
This file implements a class to represent arbitrary precision integral constant values and operations...
Type * getVoidTy()
Fetch the type representing void.
StoreInst * CreateStore(Value *Val, Value *Ptr, bool isVolatile=false)
Value * CreateIntToPtr(Value *V, Type *DestTy, const Twine &Name="")
User * getUser() const LLVM_READONLY
Returns the User that contains this Use.
Value * CreateBitCast(Value *V, Type *DestTy, const Twine &Name="")
Type * getType() const
All values are typed, get the type of this value.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory)...
Value * CreateSub(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
void SetCurrentDebugLocation(DebugLoc L)
Set location information used by debugging information.
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
void takeName(Value *V)
Transfer the name from V to this value.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree...
amdgpu Simplify well known AMD library false Value * Callee
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block...
IntegerType * getIntPtrType(LLVMContext &C, unsigned AddressSpace=0) const
Returns an integer type with size at least as big as that of a pointer in the given address space...
static bool runOnFunction(Function &F, bool PostInlining)
This means that we are dealing with an entirely unknown SCEV value, and only represent it as its LLVM...
initializer< Ty > init(const Ty &Val)
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
The instances of the Type class are immutable: once they are created, they are never changed...
DISubprogram * getSubprogram() const
Get the attached subprogram.
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This is an important base class in LLVM.
bool hasFnAttr(Attribute::AttrKind Kind) const
Return true if this function has the given attribute.
This file contains the declarations for the subclasses of Constant, which represent the different fla...
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
Compute the layout of an unsafe stack frame.
Represent the analysis usage information of a pass.
FunctionPass class - This class is used to implement most global optimizations.
ConstantRange add(const ConstantRange &Other) const
Return a new range representing the possible values resulting from an addition of a value in this ran...
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function. ...
bool doesNotCapture(unsigned OpNo) const
Determine whether this data operand is not captured.
const Value * getArraySize() const
Get the number of elements allocated.
static PointerType * getInt8PtrTy(LLVMContext &C, unsigned AS=0)
INITIALIZE_PASS_END(RegBankSelect, DEBUG_TYPE, "Assign register bank of generic virtual registers", false, false) RegBankSelect
Value * CreateMul(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Type * getAllocatedType() const
Return the type that is being allocated by the instruction.
This base class for TargetLowering contains the SelectionDAG-independent parts that can be used from ...
Value * CreateGEP(Value *Ptr, ArrayRef< Value *> IdxList, const Twine &Name="")
This is the common base class for memset/memcpy/memmove.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements...
This is the shared class of boolean and integer constants.
Type * getType() const
Return the LLVM type of this SCEV expression.
Value * CreateIntCast(Value *V, Type *DestTy, bool isSigned, const Twine &Name="")
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
Module.h This file contains the declarations for the Module class.
This class represents a range of values.
LLVM_NODISCARD T pop_back_val()
CallInst * CreateMemCpy(Value *Dst, unsigned DstAlign, Value *Src, unsigned SrcAlign, uint64_t Size, bool isVolatile=false, MDNode *TBAATag=nullptr, MDNode *TBAAStructTag=nullptr, MDNode *ScopeTag=nullptr, MDNode *NoAliasTag=nullptr)
Create and insert a memcpy between the specified pointers.
static Constant * get(Type *Ty, uint64_t V, bool isSigned=false)
If Ty is a vector type, return a Constant with a splat of the given value.
virtual const TargetSubtargetInfo * getSubtargetImpl(const Function &) const
Virtual method implemented by subclasses that returns a reference to that target's TargetSubtargetInf...
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
unsigned getObjectAlignment(const Value *V)
Returns the alignment of the object.
Class for arbitrary precision integers.
void initializeSafeStackLegacyPassPass(PassRegistry &)
void computeLayout()
Run the layout computation for all previously added objects.
Value * CreatePointerCast(Value *V, Type *DestTy, const Twine &Name="")
unsigned getFrameAlignment()
Returns the alignment of the frame.
bool replaceDbgDeclare(Value *Address, Value *NewAddress, Instruction *InsertBefore, DIBuilder &Builder, bool DerefBefore, int Offset, bool DerefAfter)
Replaces llvm.dbg.declare instruction when the address it describes is replaced with a new value...
bool doesNotAccessMemory() const
Determine if the call does not access memory.
amdgpu Simplify well known AMD library false Value Value * Arg
Instruction * SplitBlockAndInsertIfThen(Value *Cond, Instruction *SplitBefore, bool Unreachable, MDNode *BranchWeights=nullptr, DominatorTree *DT=nullptr, LoopInfo *LI=nullptr)
Split the containing block at the specified instruction - everything before SplitBefore stays in the ...
Virtual Register Rewriter
Constant * getOrInsertGlobal(StringRef Name, Type *Ty, function_ref< GlobalVariable *()> CreateGlobalCallback)
Look up the specified global in the module symbol table.
This class represents an analyzed expression in the program.
static IntegerType * getInt32Ty(LLVMContext &C)
LLVM_NODISCARD bool empty() const
StringRef getName() const
Return a constant reference to the value's name.
Establish a view to a call site for examination.
LLVM_NODISCARD std::enable_if<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type dyn_cast(const Y &Val)
CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value *> Args=None, const Twine &Name="", MDNode *FPMathTag=nullptr)
Value * CreateAnd(Value *LHS, Value *RHS, const Twine &Name="")
Value * CreatePtrToInt(Value *V, Type *DestTy, const Twine &Name="")
bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
FunTy * getCalledFunction() const
Return the function being called if this is a direct call, otherwise return null (if it's an indirect...
bool isArrayAllocation() const
Return true if there is an allocation size parameter to the allocation instruction that is not 1...
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
const BasicBlock & front() const
Module * getParent()
Get the module that this global value is contained inside of...
LLVM Value Representation.
Primary interface to the complete machine description for the target machine.
inst_iterator inst_end(Function *F)
inst_range instructions(Function *F)
bool isStaticAlloca() const
Return true if this alloca is in the entry block of the function and is a constant size...
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 IntegerType * getInt8Ty(LLVMContext &C)
Value * getRawDest() const
This visitor recursively visits a SCEV expression and re-writes it.
static BranchProbability getBranchProbStackProtector(bool IsLikely)
iterator_range< arg_iterator > args()
bool empty() const
empty - Check if the array is empty.
A wrapper class for inspecting calls to intrinsic functions.
This file describes how to lower LLVM code to machine code.
an instruction to allocate memory on the stack