51 using namespace llvm::safestack;
53 #define DEBUG_TYPE "safestack"
57 STATISTIC(NumFunctions,
"Total number of functions");
58 STATISTIC(NumUnsafeStackFunctions,
"Number of functions with unsafe stack");
59 STATISTIC(NumUnsafeStackRestorePointsFunctions,
60 "Number of functions that use setjmp or exceptions");
62 STATISTIC(NumAllocas,
"Total number of allocas");
63 STATISTIC(NumUnsafeStaticAllocas,
"Number of unsafe static allocas");
64 STATISTIC(NumUnsafeDynamicAllocas,
"Number of unsafe dynamic allocas");
65 STATISTIC(NumUnsafeByValArguments,
"Number of unsafe byval arguments");
66 STATISTIC(NumUnsafeStackRestorePoints,
"Number of setjmps and landingpads");
77 const Value *AllocaPtr;
85 return SE.getZero(Expr->
getType());
106 Value *UnsafeStackPtr =
nullptr;
114 enum { StackAlignment = 16 };
134 uint64_t getStaticAllocaAllocationSize(
const AllocaInst* AI);
157 Value *StaticTop,
bool NeedDynamicTop);
162 void moveDynamicAllocasToUnsafeStack(
Function &
F,
Value *UnsafeStackPtr,
166 bool IsSafeStackAlloca(
const Value *AllocaPtr, uint64_t AllocaSize);
169 const Value *AllocaPtr, uint64_t AllocaSize);
170 bool IsAccessSafe(
Value *Addr, uint64_t Size,
const Value *AllocaPtr,
171 uint64_t AllocaSize);
179 SafeStack() : SafeStack(nullptr) {}
185 bool doInitialization(
Module &M)
override {
196 bool runOnFunction(
Function &
F)
override;
199 uint64_t SafeStack::getStaticAllocaAllocationSize(
const AllocaInst* AI) {
205 Size *=
C->getZExtValue();
210 bool SafeStack::IsAccessSafe(
Value *Addr, uint64_t AccessSize,
211 const Value *AllocaPtr, uint64_t AllocaSize) {
212 AllocaOffsetRewriter
Rewriter(*SE, AllocaPtr);
215 uint64_t BitWidth = SE->getTypeSizeInBits(Expr->
getType());
222 bool Safe = AllocaRange.
contains(AccessRange);
225 << (isa<AllocaInst>(AllocaPtr) ?
"Alloca " :
"ByValArgument ")
226 << *AllocaPtr <<
"\n"
227 <<
" Access " << *Addr <<
"\n"
229 <<
" U: " << SE->getUnsignedRange(Expr)
230 <<
", S: " << SE->getSignedRange(Expr) <<
"\n"
231 <<
" Range " << AccessRange <<
"\n"
232 <<
" AllocaRange " << AllocaRange <<
"\n"
233 <<
" " << (Safe ?
"safe" :
"unsafe") <<
"\n");
239 const Value *AllocaPtr,
240 uint64_t AllocaSize) {
245 if (!Len)
return false;
246 return IsAccessSafe(U, Len->getZExtValue(), AllocaPtr, AllocaSize);
252 bool SafeStack::IsSafeStackAlloca(
const Value *AllocaPtr, uint64_t AllocaSize) {
261 while (!WorkList.
empty()) {
263 for (
const Use &UI : V->
uses()) {
264 auto I = cast<const Instruction>(UI.getUser());
267 switch (
I->getOpcode()) {
269 if (!IsAccessSafe(UI,
DL->getTypeStoreSize(
I->getType()), AllocaPtr,
274 case Instruction::VAArg:
278 if (V ==
I->getOperand(0)) {
280 DEBUG(
dbgs() <<
"[SafeStack] Unsafe alloca: " << *AllocaPtr
281 <<
"\n store of address: " << *
I <<
"\n");
285 if (!IsAccessSafe(UI,
DL->getTypeStoreSize(
I->getOperand(0)->getType()),
286 AllocaPtr, AllocaSize))
296 case Instruction::Invoke: {
300 if (II->getIntrinsicID() == Intrinsic::lifetime_start ||
301 II->getIntrinsicID() == Intrinsic::lifetime_end)
306 if (!IsMemIntrinsicSafe(MI, UI, AllocaPtr, AllocaSize)) {
307 DEBUG(
dbgs() <<
"[SafeStack] Unsafe alloca: " << *AllocaPtr
308 <<
"\n unsafe memintrinsic: " << *
I
325 if (!(
CS.doesNotCapture(
A - B) && (
CS.doesNotAccessMemory(
A - B) ||
326 CS.doesNotAccessMemory()))) {
327 DEBUG(
dbgs() <<
"[SafeStack] Unsafe alloca: " << *AllocaPtr
328 <<
"\n unsafe call: " << *
I <<
"\n");
336 WorkList.
push_back(cast<const Instruction>(
I));
346 Value *StackGuardVar = TL->getIRStackGuard(IRB);
350 return IRB.
CreateLoad(StackGuardVar,
"StackGuard");
353 void SafeStack::findInsts(
Function &F,
360 if (
auto AI = dyn_cast<AllocaInst>(&
I)) {
363 uint64_t Size = getStaticAllocaAllocationSize(AI);
364 if (IsSafeStackAlloca(AI, Size))
368 ++NumUnsafeStaticAllocas;
371 ++NumUnsafeDynamicAllocas;
374 }
else if (
auto RI = dyn_cast<ReturnInst>(&
I)) {
376 }
else if (
auto CI = dyn_cast<CallInst>(&
I)) {
378 if (CI->getCalledFunction() && CI->canReturnTwice())
380 }
else if (
auto LP = dyn_cast<LandingPadInst>(&
I)) {
383 }
else if (
auto II = dyn_cast<IntrinsicInst>(&
I)) {
384 if (II->getIntrinsicID() == Intrinsic::gcroot)
386 "gcroot intrinsic not compatible with safestack attribute");
390 if (!Arg.hasByValAttr())
393 DL->getTypeStoreSize(Arg.getType()->getPointerElementType());
394 if (IsSafeStackAlloca(&Arg, Size))
397 ++NumUnsafeByValArguments;
405 Value *StaticTop,
bool NeedDynamicTop) {
406 assert(StaticTop &&
"The stack top isn't set.");
408 if (StackRestorePoints.
empty())
418 if (NeedDynamicTop) {
422 "unsafe_stack_dynamic_ptr");
428 ++NumUnsafeStackRestorePoints;
431 Value *CurrentTop = DynamicTop ? IRB.
CreateLoad(DynamicTop) : StaticTop;
446 .createBranchWeights(SuccessProb.getNumerator(),
447 FailureProb.getNumerator());
454 "__stack_chk_fail", IRB.
getVoidTy(),
nullptr);
455 IRBFail.CreateCall(StackChkFail, {});
461 Value *SafeStack::moveStaticAllocasToUnsafeStack(
465 if (StaticAllocas.
empty() && ByValArguments.
empty())
472 SSC.removeAllMarkers();
476 if (StackGuardSlot) {
479 std::max(
DL->getPrefTypeAlignment(Ty), StackGuardSlot->
getAlignment());
480 SSL.addObject(StackGuardSlot, getStaticAllocaAllocationSize(StackGuardSlot),
481 Align, SSC.getFullLiveRange());
484 for (
Argument *Arg : ByValArguments) {
486 uint64_t Size =
DL->getTypeStoreSize(Ty);
491 unsigned Align = std::max((
unsigned)
DL->getPrefTypeAlignment(Ty),
492 Arg->getParamAlignment());
493 SSL.addObject(Arg, Size, Align, SSC.getFullLiveRange());
498 uint64_t Size = getStaticAllocaAllocationSize(AI);
504 std::max((
unsigned)
DL->getPrefTypeAlignment(Ty), AI->
getAlignment());
506 SSL.addObject(AI, Size, Align, SSC.getLiveRange(AI));
510 unsigned FrameAlignment = SSL.getFrameAlignment();
514 if (FrameAlignment > StackAlignment) {
526 if (StackGuardSlot) {
527 unsigned Offset = SSL.getObjectOffset(StackGuardSlot);
538 for (
Argument *Arg : ByValArguments) {
539 unsigned Offset = SSL.getObjectOffset(Arg);
542 uint64_t Size =
DL->getTypeStoreSize(Ty);
549 Arg->getName() +
".unsafe-byval");
554 Arg->replaceAllUsesWith(NewArg);
556 IRB.
CreateMemCpy(Off, Arg, Size, Arg->getParamAlignment());
562 unsigned Offset = SSL.getObjectOffset(AI);
564 uint64_t Size = getStaticAllocaAllocationSize(AI);
573 std::string
Name = std::string(AI->
getName()) +
".unsafe";
579 if (
auto *PHI = dyn_cast<PHINode>(User))
580 InsertBefore = PHI->getIncomingBlock(U)->getTerminator();
585 Value *Off = IRBUser.CreateGEP(BasePointer,
589 if (
auto *PHI = dyn_cast<PHINode>(User)) {
592 auto *BB = PHI->getIncomingBlock(U);
593 for (
unsigned I = 0;
I < PHI->getNumIncomingValues(); ++
I)
594 if (PHI->getIncomingBlock(
I) == BB)
595 PHI->setIncomingValue(
I, Replacement);
607 unsigned FrameSize =
alignTo(SSL.getFrameSize(), StackAlignment);
614 "unsafe_stack_static_top");
619 void SafeStack::moveDynamicAllocasToUnsafeStack(
629 if (ArraySize->
getType() != IntPtrTy)
633 uint64_t TySize =
DL->getTypeAllocSize(Ty);
640 unsigned Align = std::max(
641 std::max((
unsigned)
DL->getPrefTypeAlignment(Ty), AI->
getAlignment()),
642 (
unsigned)StackAlignment);
645 Value *NewTop = IRB.CreateIntToPtr(
646 IRB.CreateAnd(SP,
ConstantInt::get(IntPtrTy, ~uint64_t(Align - 1))),
650 IRB.CreateStore(NewTop, UnsafeStackPtr);
652 IRB.CreateStore(NewTop, DynamicTop);
654 Value *NewAI = IRB.CreatePointerCast(NewTop, AI->
getType());
659 AI->replaceAllUsesWith(NewAI);
660 AI->eraseFromParent();
663 if (!DynamicAllocas.empty()) {
671 if (II->getIntrinsicID() == Intrinsic::stacksave) {
675 II->replaceAllUsesWith(LI);
676 II->eraseFromParent();
677 }
else if (II->getIntrinsicID() == Intrinsic::stackrestore) {
682 II->eraseFromParent();
688 bool SafeStack::runOnFunction(
Function &F) {
692 DEBUG(
dbgs() <<
"[SafeStack] safestack is not requested"
693 " for this function\n");
698 DEBUG(
dbgs() <<
"[SafeStack] function definition"
699 " is not available\n");
706 SE = &getAnalysis<ScalarEvolutionWrapperPass>().getSE();
724 findInsts(F, StaticAllocas, DynamicAllocas, ByValArguments, Returns,
727 if (StaticAllocas.
empty() && DynamicAllocas.
empty() &&
728 ByValArguments.
empty() && StackRestorePoints.
empty())
731 if (!StaticAllocas.
empty() || !DynamicAllocas.
empty() ||
732 !ByValArguments.
empty())
733 ++NumUnsafeStackFunctions;
735 if (!StackRestorePoints.
empty())
736 ++NumUnsafeStackRestorePointsFunctions;
739 UnsafeStackPtr = TL->getSafeStackPointerLocation(IRB);
744 IRB.
CreateLoad(UnsafeStackPtr,
false,
"unsafe_stack_ptr");
758 checkStackGuard(IRBRet, F, *RI, StackGuardSlot, StackGuard);
765 moveStaticAllocasToUnsafeStack(IRB, F, StaticAllocas, ByValArguments,
766 Returns, BasePointer, StackGuardSlot);
774 AllocaInst *DynamicTop = createStackRestorePoints(
775 IRB, F, StackRestorePoints, StaticTop, !DynamicAllocas.
empty());
778 moveDynamicAllocasToUnsafeStack(F, UnsafeStackPtr, DynamicTop,
787 DEBUG(
dbgs() <<
"[SafeStack] safestack applied\n");
795 "Safe Stack instrumentation pass",
false,
false)
800 return new SafeStack(TM);
Return a value (possibly void), from a function.
SymbolTableList< Instruction >::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
void push_back(const T &Elt)
A parsed version of the target data layout string in and methods for querying it. ...
bool replaceDbgDeclareForAlloca(AllocaInst *AI, Value *NewAllocaAddress, DIBuilder &Builder, bool Deref, int Offset=0)
Replaces llvm.dbg.declare instruction when the alloca it describes is replaced with a new value...
iterator_range< use_iterator > uses()
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function. ...
LLVM Argument representation.
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...
Value * CreateICmpNE(Value *LHS, Value *RHS, const Twine &Name="")
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
STATISTIC(NumFunctions,"Total number of functions")
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
A Module instance is used to store all the information related to an LLVM module. ...
Compute live ranges of allocas.
The main scalar evolution driver.
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...
FunctionType * getType(LLVMContext &Context, ID id, ArrayRef< Type * > Tys=None)
Return the function type for an intrinsic.
Type * getPointerElementType() const
StringRef getName() const
Return a constant reference to the value's name.
bool isArrayAllocation() const
Return true if there is an allocation size parameter to the allocation instruction that is not 1...
safe Safe Stack instrumentation pass
AllocaInst * CreateAlloca(Type *Ty, Value *ArraySize=nullptr, const Twine &Name="")
AnalysisUsage & addRequired()
inst_iterator inst_begin(Function *F)
A Use represents the edge between a Value definition and its users.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Type * getVoidTy()
Fetch the type representing void.
LLVM_NODISCARD bool empty() const
StoreInst * CreateStore(Value *Val, Value *Ptr, bool isVolatile=false)
Value * CreateIntToPtr(Value *V, Type *DestTy, const Twine &Name="")
Value * CreateBitCast(Value *V, Type *DestTy, const Twine &Name="")
bool contains(const APInt &Val) const
Return true if the specified value is in the set.
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)
static GCRegistry::Add< OcamlGC > B("ocaml","ocaml 3.10-compatible GC")
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.
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block...
static GCRegistry::Add< CoreCLRGC > E("coreclr","CoreCLR-compatible GC")
LoadInst * CreateLoad(Value *Ptr, const char *Name)
This means that we are dealing with an entirely unknown SCEV value, and only represent it as its LLVM...
* if(!EatIfPresent(lltok::kw_thread_local)) return false
ParseOptionalThreadLocal := /*empty.
constexpr bool isPowerOf2_32(uint32_t Value)
isPowerOf2_32 - This function returns true if the argument is a power of two > 0. ...
Constant * getOrInsertFunction(StringRef Name, FunctionType *T, AttributeSet AttributeList)
Look up the specified function in the module symbol table.
The instances of the Type class are immutable: once they are created, they are never changed...
Type * getType() const
Return the LLVM type of this SCEV expression.
Constant * getOrInsertGlobal(StringRef Name, Type *Ty)
Look up the specified global in the module symbol table.
This is an important base class in LLVM.
PointerType * getType() const
Overload to return most specific pointer type.
This file contains the declarations for the subclasses of Constant, which represent the different fla...
unsigned getAlignment() const
Return the alignment of the memory that is being allocated by the instruction.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
#define INITIALIZE_TM_PASS_END(passName, arg, name, cfg, analysis)
Target machine pass initializer for passes with dependencies.
Value * getRawDest() const
Compute the layout of an unsafe stack frame.
Represent the analysis usage information of a pass.
User * getUser() const
Returns the User that contains this Use.
FunctionPass class - This class is used to implement most global optimizations.
FunctionPass * createSafeStackPass(const TargetMachine *TM=nullptr)
This pass splits the stack into a safe stack and an unsafe stack to protect against stack-based overf...
bool empty() const
empty - Check if the array is empty.
bool replaceDbgDeclare(Value *Address, Value *NewAddress, Instruction *InsertBefore, DIBuilder &Builder, bool Deref, int Offset)
Replaces llvm.dbg.declare instruction when the address it describes is replaced with a new value...
static PointerType * getInt8PtrTy(LLVMContext &C, unsigned AS=0)
ConstantRange add(const ConstantRange &Other) const
Return a new range representing the possible values resulting from an addition of a value in this ran...
User::const_op_iterator arg_iterator
arg_iterator - The type of iterator to use when looping over actual arguments at this call site...
Value * CreateMul(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
This base class for TargetLowering contains the SelectionDAG-independent parts that can be used from ...
virtual const TargetSubtargetInfo * getSubtargetImpl(const Function &) const
Virtual method implemented by subclasses that returns a reference to that target's TargetSubtargetInf...
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.
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...
bool isStaticAlloca() const
Return true if this alloca is in the entry block of the function and is a constant size...
Module.h This file contains the declarations for the Module class.
Type * getType() const
All values are typed, get the type of this value.
virtual const TargetLowering * getTargetLowering() const
pgo instr PGO instrumentation
This class represents a range of values.
INITIALIZE_TM_PASS_BEGIN(SafeStack,"safe-stack","Safe Stack instrumentation pass", false, false) INITIALIZE_TM_PASS_END(SafeStack
TerminatorInst * 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 ...
Value * getLength() const
LLVM_NODISCARD T pop_back_val()
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.
LLVM_NODISCARD bool isa(const Y &Val)
static GCRegistry::Add< ShadowStackGC > C("shadow-stack","Very portable GC for uncooperative code generators")
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Value * CreateGEP(Value *Ptr, ArrayRef< Value * > IdxList, const Twine &Name="")
Class for arbitrary precision integers.
safe Safe Stack instrumentation false
Virtual Register Rewriter
const DataLayout & getDataLayout() const
Get the data layout for the module's target platform.
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
CallInst * CreateMemCpy(Value *Dst, Value *Src, uint64_t Size, unsigned Align, bool isVolatile=false, MDNode *TBAATag=nullptr, MDNode *TBAAStructTag=nullptr, MDNode *ScopeTag=nullptr, MDNode *NoAliasTag=nullptr)
Create and insert a memcpy between the specified pointers.
This class represents an analyzed expression in the program.
static IntegerType * getInt32Ty(LLVMContext &C)
void initializeSafeStackPass(PassRegistry &)
bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
ImmutableCallSite - 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)
Value * CreateAnd(Value *LHS, Value *RHS, const Twine &Name="")
Value * CreatePtrToInt(Value *V, Type *DestTy, const Twine &Name="")
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.
const Value * getArraySize() const
Get the number of elements allocated.
Primary interface to the complete machine description for the target machine.
inst_iterator inst_end(Function *F)
inst_range instructions(Function *F)
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.
Type * getAllocatedType() const
Return the type that is being allocated by the instruction.
static GCRegistry::Add< ErlangGC > A("erlang","erlang-compatible garbage collector")
static IntegerType * getInt8Ty(LLVMContext &C)
This visitor recursively visits a SCEV expression and re-writes it.
static BranchProbability getBranchProbStackProtector(bool IsLikely)
iterator_range< arg_iterator > args()
A wrapper class for inspecting calls to intrinsic functions.
LLVMContext & getContext() const
Get the global data context.
This file describes how to lower LLVM code to machine code.
an instruction to allocate memory on the stack