45 #define DEBUG_TYPE "safestack"
49 STATISTIC(NumFunctions,
"Total number of functions");
50 STATISTIC(NumUnsafeStackFunctions,
"Number of functions with unsafe stack");
51 STATISTIC(NumUnsafeStackRestorePointsFunctions,
52 "Number of functions that use setjmp or exceptions");
54 STATISTIC(NumAllocas,
"Total number of allocas");
55 STATISTIC(NumUnsafeStaticAllocas,
"Number of unsafe static allocas");
56 STATISTIC(NumUnsafeDynamicAllocas,
"Number of unsafe dynamic allocas");
57 STATISTIC(NumUnsafeStackRestorePoints,
"Number of setjmps and landingpads");
76 while (!WorkList.
empty()) {
78 for (
const Use &UI : V->
uses()) {
79 auto I = cast<const Instruction>(UI.getUser());
80 assert(V == UI.get());
82 switch (
I->getOpcode()) {
86 case Instruction::VAArg:
90 if (V ==
I->getOperand(0))
96 case Instruction::GetElementPtr:
97 if (!cast<const GetElementPtrInst>(
I)->hasAllConstantIndices())
114 case Instruction::BitCast:
115 case Instruction::IntToPtr:
117 case Instruction::PtrToInt:
122 WorkList.
push_back(cast<const Instruction>(
I));
126 case Instruction::Invoke: {
139 if (
A->get() == V && !
CS.doesNotCapture(
A - B))
176 enum { StackAlignment = 16 };
208 Value *StaticTop,
bool NeedDynamicTop);
213 void moveDynamicAllocasToUnsafeStack(
Function &
F,
Value *UnsafeStackPtr,
227 virtual bool doInitialization(
Module &M) {
244 const char *kUnsafeStackPtrVar =
"__safestack_unsafe_stack_ptr";
246 auto UnsafeStackPtr =
247 dyn_cast_or_null<GlobalVariable>(M.
getNamedValue(kUnsafeStackPtrVar));
249 if (!UnsafeStackPtr) {
256 0, kUnsafeStackPtrVar,
261 if (UnsafeStackPtr->getValueType() != StackPtrTy) {
265 if (!UnsafeStackPtr->isThreadLocal()) {
270 return UnsafeStackPtr;
279 if (
auto AI = dyn_cast<AllocaInst>(&
I)) {
282 if (IsSafeStackAlloca(AI))
286 ++NumUnsafeStaticAllocas;
289 ++NumUnsafeDynamicAllocas;
292 }
else if (
auto RI = dyn_cast<ReturnInst>(&
I)) {
294 }
else if (
auto CI = dyn_cast<CallInst>(&
I)) {
296 if (CI->getCalledFunction() && CI->canReturnTwice())
298 }
else if (
auto LP = dyn_cast<LandingPadInst>(&
I)) {
301 }
else if (
auto II = dyn_cast<IntrinsicInst>(&
I)) {
302 if (II->getIntrinsicID() == Intrinsic::gcroot)
304 "gcroot intrinsic not compatible with safestack attribute");
310 SafeStack::createStackRestorePoints(
Function &F,
312 Value *StaticTop,
bool NeedDynamicTop) {
313 if (StackRestorePoints.
empty())
317 ? cast<Instruction>(StaticTop)->getNextNode()
331 "unsafe_stack_dynamic_ptr");
336 StaticTop = IRB.CreateLoad(UnsafeStackPtr,
false,
"unsafe_stack_ptr");
339 IRB.CreateStore(StaticTop, DynamicTop);
343 ++NumUnsafeStackRestorePoints;
345 IRB.SetInsertPoint(cast<Instruction>(
I->getNextNode()));
346 Value *CurrentTop = DynamicTop ? IRB.
CreateLoad(DynamicTop) : StaticTop;
347 IRB.CreateStore(CurrentTop, UnsafeStackPtr);
354 SafeStack::moveStaticAllocasToUnsafeStack(
Function &F,
357 if (StaticAllocas.
empty())
370 IRB.CreateLoad(UnsafeStackPtr,
false,
"unsafe_stack_ptr");
371 assert(BasePointer->getType() == StackPtrTy);
374 IRB.SetInsertPoint(RI);
375 IRB.CreateStore(BasePointer, UnsafeStackPtr);
379 unsigned MaxAlignment = 0;
383 std::max((
unsigned)
DL->getPrefTypeAlignment(Ty), AI->
getAlignment());
384 if (Align > MaxAlignment)
385 MaxAlignment =
Align;
388 if (MaxAlignment > StackAlignment) {
391 IRB.SetInsertPoint(cast<Instruction>(BasePointer->getNextNode()));
392 BasePointer = cast<Instruction>(IRB.CreateIntToPtr(
393 IRB.CreateAnd(IRB.CreatePtrToInt(BasePointer, IntPtrTy),
399 int64_t StaticOffset = 0;
403 auto CArraySize = cast<ConstantInt>(AI->
getArraySize());
406 uint64_t Size =
DL->getTypeAllocSize(Ty) * CArraySize->getZExtValue();
412 std::max((
unsigned)
DL->getPrefTypeAlignment(Ty), AI->
getAlignment());
416 StaticOffset += Size;
419 Value *Off = IRB.CreateGEP(BasePointer,
422 if (AI->
hasName() && isa<Instruction>(NewAI))
423 cast<Instruction>(NewAI)->takeName(AI);
437 IRB.SetInsertPoint(cast<Instruction>(BasePointer->getNextNode()));
441 "unsafe_stack_static_top");
442 IRB.CreateStore(StaticTop, UnsafeStackPtr);
446 void SafeStack::moveDynamicAllocasToUnsafeStack(
456 if (ArraySize->
getType() != IntPtrTy)
457 ArraySize = IRB.CreateIntCast(ArraySize, IntPtrTy,
false);
460 uint64_t TySize =
DL->getTypeAllocSize(Ty);
463 Value *
SP = IRB.CreatePtrToInt(IRB.CreateLoad(UnsafeStackPtr), IntPtrTy);
464 SP = IRB.CreateSub(SP, Size);
467 unsigned Align = std::max(
468 std::max((
unsigned)
DL->getPrefTypeAlignment(Ty), AI->
getAlignment()),
469 (
unsigned)StackAlignment);
472 Value *NewTop = IRB.CreateIntToPtr(
473 IRB.CreateAnd(SP,
ConstantInt::get(IntPtrTy, ~uint64_t(Align - 1))),
477 IRB.CreateStore(NewTop, UnsafeStackPtr);
479 IRB.CreateStore(NewTop, DynamicTop);
486 AI->replaceAllUsesWith(NewAI);
487 AI->eraseFromParent();
490 if (!DynamicAllocas.empty()) {
498 if (II->getIntrinsicID() == Intrinsic::stacksave) {
502 II->replaceAllUsesWith(LI);
503 II->eraseFromParent();
504 }
else if (II->getIntrinsicID() == Intrinsic::stackrestore) {
506 Instruction *
SI = IRB.CreateStore(II->getArgOperand(0), UnsafeStackPtr);
508 assert(II->use_empty());
509 II->eraseFromParent();
515 bool SafeStack::runOnFunction(
Function &F) {
516 auto AA = &getAnalysis<AliasAnalysis>();
521 DEBUG(
dbgs() <<
"[SafeStack] safestack is not requested"
522 " for this function\n");
527 DEBUG(
dbgs() <<
"[SafeStack] function definition"
528 " is not available\n");
544 if (AA->onlyReadsMemory(&F)) {
546 DEBUG(
dbgs() <<
"[SafeStack] function only reads memory\n");
565 findInsts(F, StaticAllocas, DynamicAllocas, Returns, StackRestorePoints);
567 if (StaticAllocas.
empty() && DynamicAllocas.
empty() &&
568 StackRestorePoints.
empty())
571 if (!StaticAllocas.
empty() || !DynamicAllocas.
empty())
572 ++NumUnsafeStackFunctions;
574 if (!StackRestorePoints.
empty())
575 ++NumUnsafeStackRestorePointsFunctions;
578 UnsafeStackPtr = getOrCreateUnsafeStackPtr(*F.
getParent());
581 Value *StaticTop = moveStaticAllocasToUnsafeStack(F, StaticAllocas, Returns);
589 AllocaInst *DynamicTop = createStackRestorePoints(
590 F, StackRestorePoints, StaticTop, !DynamicAllocas.
empty());
593 moveDynamicAllocasToUnsafeStack(F, UnsafeStackPtr, DynamicTop,
596 DEBUG(
dbgs() <<
"[SafeStack] safestack applied\n");
604 "Safe Stack instrumentation pass",
false,
false)
ReturnInst - Return a value (possibly void), from a function.
iplist< Instruction >::iterator eraseFromParent()
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. ...
AllocaInst * CreateAlloca(Type *Ty, Value *ArraySize=nullptr, const Twine &Name="")
iterator_range< use_iterator > uses()
LoadInst * CreateLoad(Value *Ptr, const char *Name)
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. ...
STATISTIC(NumFunctions,"Total number of functions")
A Module instance is used to store all the information related to an LLVM module. ...
FunctionPass * createSafeStackPass()
This pass splits the stack into a safe stack and an unsafe stack to protect against stack-based overf...
Externally visible function.
FunctionType * getType(LLVMContext &Context, ID id, ArrayRef< Type * > Tys=None)
Return the function type for an intrinsic.
AttrBuilder & addAttribute(Attribute::AttrKind Val)
Add an attribute to the builder.
User::const_op_iterator arg_iterator
arg_iterator - The type of iterator to use when looping over actual arguments at this call site...
INITIALIZE_PASS_BEGIN(SafeStack,"safe-stack","Safe Stack instrumentation pass", false, false) INITIALIZE_PASS_END(SafeStack
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(const char *reason, bool gen_crash_diag=true)
Reports a serious error, calling any installed error handler.
StringRef getName() const
Return a constant reference to the value's name.
safe Safe Stack instrumentation pass
AnalysisUsage & addRequired()
#define INITIALIZE_PASS_DEPENDENCY(depName)
inst_iterator inst_begin(Function *F)
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
T LLVM_ATTRIBUTE_UNUSED_RESULT pop_back_val()
A Use represents the edge between a Value definition and its users.
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
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...
bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory)...
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
void removeAttributes(unsigned i, AttributeSet attr)
removes the attributes from the list of attributes.
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...
* if(!EatIfPresent(lltok::kw_thread_local)) return false
ParseOptionalThreadLocal := /*empty.
The instances of the Type class are immutable: once they are created, they are never changed...
This is an important base class in LLVM.
PointerType * getType() const
getType - 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
getAlignment - 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.
Represent the analysis usage information of a pass.
FunctionPass class - This class is used to implement most global optimizations.
LLVM_ATTRIBUTE_UNUSED_RESULT bool isa(const Y &Val)
bool empty() const
empty - Check if the array is empty.
static PointerType * getInt8PtrTy(LLVMContext &C, unsigned AS=0)
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.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
bool isStaticAlloca() const
isStaticAlloca - Return true if this alloca is in the entry block of the function and is a constant s...
Module.h This file contains the declarations for the Module class.
Type * getType() const
All values are typed, get the type of this value.
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.
const BasicBlock & getEntryBlock() const
static cl::opt< AlignMode > Align(cl::desc("Load/store alignment support"), cl::Hidden, cl::init(NoStrictAlign), cl::values(clEnumValN(StrictAlign,"aarch64-strict-align","Disallow all unaligned memory accesses"), clEnumValN(NoStrictAlign,"aarch64-no-strict-align","Allow unaligned memory accesses"), clEnumValEnd))
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool replaceDbgDeclareForAlloca(AllocaInst *AI, Value *NewAllocaAddress, DIBuilder &Builder, bool Deref)
Replaces llvm.dbg.declare instruction when an alloca is replaced with a new value.
safe Safe Stack instrumentation false
LLVM_ATTRIBUTE_UNUSED_RESULT std::enable_if< !is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type dyn_cast(const Y &Val)
uint64_t RoundUpToAlignment(uint64_t Value, uint64_t Align)
Returns the next integer (mod 2**64) that is greater than or equal to Value and is a multiple of Alig...
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.
static IntegerType * getInt32Ty(LLVMContext &C)
void initializeSafeStackPass(PassRegistry &)
iterator_range< inst_iterator > inst_range(Function *F)
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.
Module * getParent()
Get the module that this global value is contained inside of...
LLVM Value Representation.
const Value * getArraySize() const
getArraySize - Get the number of elements allocated.
bool isPowerOf2_32(uint32_t Value)
isPowerOf2_32 - This function returns true if the argument is a power of two > 0. ...
inst_iterator inst_end(Function *F)
iterator getFirstInsertionPt()
Returns an iterator to the first instruction in this block that is suitable for inserting a non-PHI i...
Type * getAllocatedType() const
getAllocatedType - Return the type that is being allocated by the instruction.
Stack protection required.
static IntegerType * getInt8Ty(LLVMContext &C)
GlobalValue * getNamedValue(StringRef Name) const
Return the global value in the module with the specified name, of arbitrary type. ...
IntrinsicInst - A useful wrapper class for inspecting calls to intrinsic functions.
LLVMContext & getContext() const
Get the global data context.
AllocaInst - an instruction to allocate memory on the stack.