mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-11-08 03:18:19 +00:00
Add the heuristic to differentiate SSPStrong from SSPRequired.
The requirements of the strong heuristic are: * A Protector is required for functions which contain an array, regardless of type or length. * A Protector is required for functions which contain a structure/union which contains an array, regardless of type or length. Note, there is no limit to the depth of nesting. * A protector is required when the address of a local variable (i.e., stack based variable) is exposed. (E.g., such as through a local whose address is taken as part of the RHS of an assignment or a local whose address is taken as part of a function argument.) git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@173231 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -825,7 +825,11 @@ example:
|
|||||||
placed on the stack before the local variables that's checked upon
|
placed on the stack before the local variables that's checked upon
|
||||||
return from the function to see if it has been overwritten. A
|
return from the function to see if it has been overwritten. A
|
||||||
heuristic is used to determine if a function needs stack protectors
|
heuristic is used to determine if a function needs stack protectors
|
||||||
or not.
|
or not. The heuristic used will enable protectors for functions with:
|
||||||
|
- Character arrays larger than ``ssp-buffer-size`` (default 8).
|
||||||
|
- Aggregates containing character arrays larger than ``ssp-buffer-size``.
|
||||||
|
- Calls to alloca() with variable sizes or constant sizes greater than
|
||||||
|
``ssp-buffer-size``.
|
||||||
|
|
||||||
If a function that has an ``ssp`` attribute is inlined into a
|
If a function that has an ``ssp`` attribute is inlined into a
|
||||||
function that doesn't have an ``ssp`` attribute, then the resulting
|
function that doesn't have an ``ssp`` attribute, then the resulting
|
||||||
@@ -841,8 +845,15 @@ example:
|
|||||||
an ``sspreq`` attribute.
|
an ``sspreq`` attribute.
|
||||||
``sspstrong``
|
``sspstrong``
|
||||||
This attribute indicates that the function should emit a stack smashing
|
This attribute indicates that the function should emit a stack smashing
|
||||||
protector. Currently this attribute has the same effect as
|
protector. This attribute causes a strong heuristic to be used when
|
||||||
``sspreq``. This overrides the ``ssp`` function attribute.
|
determining if a function needs stack protectors. The strong heuristic
|
||||||
|
will enable protectors for functions with:
|
||||||
|
- Arrays of any size and type
|
||||||
|
- Aggregates containing an array of any size and type.
|
||||||
|
- Calls to alloca().
|
||||||
|
- Local variables that have had their address taken.
|
||||||
|
|
||||||
|
This overrides the ``ssp`` function attribute.
|
||||||
|
|
||||||
If a function that has an ``sspstrong`` attribute is inlined into a
|
If a function that has an ``sspstrong`` attribute is inlined into a
|
||||||
function that doesn't have an ``sspstrong`` attribute, then the
|
function that doesn't have an ``sspstrong`` attribute, then the
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
#define DEBUG_TYPE "stack-protector"
|
#define DEBUG_TYPE "stack-protector"
|
||||||
#include "llvm/CodeGen/Passes.h"
|
#include "llvm/CodeGen/Passes.h"
|
||||||
|
#include "llvm/ADT/SmallPtrSet.h"
|
||||||
|
#include "llvm/ADT/Statistic.h"
|
||||||
#include "llvm/ADT/Triple.h"
|
#include "llvm/ADT/Triple.h"
|
||||||
#include "llvm/Analysis/Dominators.h"
|
#include "llvm/Analysis/Dominators.h"
|
||||||
#include "llvm/IR/Attributes.h"
|
#include "llvm/IR/Attributes.h"
|
||||||
@@ -32,6 +34,10 @@
|
|||||||
#include "llvm/Target/TargetOptions.h"
|
#include "llvm/Target/TargetOptions.h"
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
|
STATISTIC(NumFunProtected, "Number of functions protected");
|
||||||
|
STATISTIC(NumAddrTaken, "Number of local variables that have their address"
|
||||||
|
" taken.");
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
class StackProtector : public FunctionPass {
|
class StackProtector : public FunctionPass {
|
||||||
/// TLI - Keep a pointer of a TargetLowering to consult for determining
|
/// TLI - Keep a pointer of a TargetLowering to consult for determining
|
||||||
@@ -43,6 +49,12 @@ namespace {
|
|||||||
|
|
||||||
DominatorTree *DT;
|
DominatorTree *DT;
|
||||||
|
|
||||||
|
/// VisitedPHIs - The set of PHI nodes visited when determining
|
||||||
|
/// if a variable's reference has been taken. This set
|
||||||
|
/// is maintained to ensure we don't visit the same PHI node multiple
|
||||||
|
/// times.
|
||||||
|
SmallPtrSet<const PHINode*, 16> VisitedPHIs;
|
||||||
|
|
||||||
/// InsertStackProtectors - Insert code into the prologue and epilogue of
|
/// InsertStackProtectors - Insert code into the prologue and epilogue of
|
||||||
/// the function.
|
/// the function.
|
||||||
///
|
///
|
||||||
@@ -58,11 +70,15 @@ namespace {
|
|||||||
/// ContainsProtectableArray - Check whether the type either is an array or
|
/// ContainsProtectableArray - Check whether the type either is an array or
|
||||||
/// contains an array of sufficient size so that we need stack protectors
|
/// contains an array of sufficient size so that we need stack protectors
|
||||||
/// for it.
|
/// for it.
|
||||||
bool ContainsProtectableArray(Type *Ty, bool InStruct = false) const;
|
bool ContainsProtectableArray(Type *Ty, bool Strong = false,
|
||||||
|
bool InStruct = false) const;
|
||||||
|
|
||||||
|
/// \brief Check whether a stack allocation has its address taken.
|
||||||
|
bool HasAddressTaken(const Instruction *AI);
|
||||||
|
|
||||||
/// RequiresStackProtector - Check whether or not this function needs a
|
/// RequiresStackProtector - Check whether or not this function needs a
|
||||||
/// stack protector based upon the stack protector level.
|
/// stack protector based upon the stack protector level.
|
||||||
bool RequiresStackProtector() const;
|
bool RequiresStackProtector();
|
||||||
public:
|
public:
|
||||||
static char ID; // Pass identification, replacement for typeid.
|
static char ID; // Pass identification, replacement for typeid.
|
||||||
StackProtector() : FunctionPass(ID), TLI(0) {
|
StackProtector() : FunctionPass(ID), TLI(0) {
|
||||||
@@ -96,15 +112,21 @@ bool StackProtector::runOnFunction(Function &Fn) {
|
|||||||
|
|
||||||
if (!RequiresStackProtector()) return false;
|
if (!RequiresStackProtector()) return false;
|
||||||
|
|
||||||
|
++NumFunProtected;
|
||||||
return InsertStackProtectors();
|
return InsertStackProtectors();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ContainsProtectableArray - Check whether the type either is an array or
|
/// ContainsProtectableArray - Check whether the type either is an array or
|
||||||
/// contains a char array of sufficient size so that we need stack protectors
|
/// contains a char array of sufficient size so that we need stack protectors
|
||||||
/// for it.
|
/// for it.
|
||||||
bool StackProtector::ContainsProtectableArray(Type *Ty, bool InStruct) const {
|
bool StackProtector::ContainsProtectableArray(Type *Ty, bool Strong,
|
||||||
|
bool InStruct) const {
|
||||||
if (!Ty) return false;
|
if (!Ty) return false;
|
||||||
if (ArrayType *AT = dyn_cast<ArrayType>(Ty)) {
|
if (ArrayType *AT = dyn_cast<ArrayType>(Ty)) {
|
||||||
|
// In strong mode any array, regardless of type and size, triggers a
|
||||||
|
// protector
|
||||||
|
if (Strong)
|
||||||
|
return true;
|
||||||
const TargetMachine &TM = TLI->getTargetMachine();
|
const TargetMachine &TM = TLI->getTargetMachine();
|
||||||
if (!AT->getElementType()->isIntegerTy(8)) {
|
if (!AT->getElementType()->isIntegerTy(8)) {
|
||||||
Triple Trip(TM.getTargetTriple());
|
Triple Trip(TM.getTargetTriple());
|
||||||
@@ -126,28 +148,68 @@ bool StackProtector::ContainsProtectableArray(Type *Ty, bool InStruct) const {
|
|||||||
|
|
||||||
for (StructType::element_iterator I = ST->element_begin(),
|
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, true))
|
if (ContainsProtectableArray(*I, Strong, true))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// RequiresStackProtector - Check whether or not this function needs a stack
|
bool StackProtector::HasAddressTaken(const Instruction *AI) {
|
||||||
/// protector based upon the stack protector level. The heuristic we use is to
|
for (Value::const_use_iterator UI = AI->use_begin(), UE = AI->use_end();
|
||||||
/// add a guard variable to functions that call alloca, and functions with
|
UI != UE; ++UI) {
|
||||||
/// buffers larger than SSPBufferSize bytes.
|
const User *U = *UI;
|
||||||
bool StackProtector::RequiresStackProtector() const {
|
if (const StoreInst *SI = dyn_cast<StoreInst>(U)) {
|
||||||
|
if (AI == SI->getValueOperand())
|
||||||
|
return true;
|
||||||
|
} else if (const PtrToIntInst *SI = dyn_cast<PtrToIntInst>(U)) {
|
||||||
|
if (AI == SI->getOperand(0))
|
||||||
|
return true;
|
||||||
|
} else if (isa<CallInst>(U)) {
|
||||||
|
return true;
|
||||||
|
} else if (isa<InvokeInst>(U)) {
|
||||||
|
return true;
|
||||||
|
} else if (const SelectInst *SI = dyn_cast<SelectInst>(U)) {
|
||||||
|
if (HasAddressTaken(SI))
|
||||||
|
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 (HasAddressTaken(PN))
|
||||||
|
return true;
|
||||||
|
} else if (const GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(U)) {
|
||||||
|
if (HasAddressTaken(GEP))
|
||||||
|
return true;
|
||||||
|
} else if (const BitCastInst *BI = dyn_cast<BitCastInst>(U)) {
|
||||||
|
if (HasAddressTaken(BI))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Check whether or not this function needs a stack protector based
|
||||||
|
/// upon the stack protector level.
|
||||||
|
///
|
||||||
|
/// We use two heuristics: a standard (ssp) and strong (sspstrong).
|
||||||
|
/// The standard heuristic which will add a guard variable to functions that
|
||||||
|
/// call alloca with a either a variable size or a size >= SSPBufferSize,
|
||||||
|
/// functions with character buffers larger than SSPBufferSize, and functions
|
||||||
|
/// with aggregates containing character buffers larger than SSPBufferSize. The
|
||||||
|
/// strong heuristic will add a guard variables to functions that call alloca
|
||||||
|
/// regardless of size, functions with any buffer regardless of type and size,
|
||||||
|
/// functions with aggregates that contain any buffer regardless of type and
|
||||||
|
/// size, and functions that contain stack-based variables that have had their
|
||||||
|
/// address taken.
|
||||||
|
bool StackProtector::RequiresStackProtector() {
|
||||||
|
bool Strong = false;
|
||||||
if (F->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
|
if (F->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
|
||||||
Attribute::StackProtectReq))
|
Attribute::StackProtectReq))
|
||||||
return true;
|
return true;
|
||||||
|
else if (F->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
|
||||||
// FIXME: Dummy SSP-strong implementation. Default to required until
|
|
||||||
// strong heuristic is implemented.
|
|
||||||
if (F->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
|
|
||||||
Attribute::StackProtectStrong))
|
Attribute::StackProtectStrong))
|
||||||
return true;
|
Strong = true;
|
||||||
|
else if (!F->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
|
||||||
if (!F->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
|
|
||||||
Attribute::StackProtect))
|
Attribute::StackProtect))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -155,15 +217,33 @@ bool StackProtector::RequiresStackProtector() const {
|
|||||||
BasicBlock *BB = I;
|
BasicBlock *BB = I;
|
||||||
|
|
||||||
for (BasicBlock::iterator
|
for (BasicBlock::iterator
|
||||||
II = BB->begin(), IE = BB->end(); II != IE; ++II)
|
II = BB->begin(), IE = BB->end(); II != IE; ++II) {
|
||||||
if (AllocaInst *AI = dyn_cast<AllocaInst>(II)) {
|
if (AllocaInst *AI = dyn_cast<AllocaInst>(II)) {
|
||||||
if (AI->isArrayAllocation())
|
if (AI->isArrayAllocation()) {
|
||||||
// This is a call to alloca with a variable size. Emit stack
|
// SSP-Strong: Enable protectors for any call to alloca, regardless
|
||||||
// protectors.
|
// of size.
|
||||||
|
if (Strong)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (ContainsProtectableArray(AI->getAllocatedType()))
|
if (const ConstantInt *CI =
|
||||||
|
dyn_cast<ConstantInt>(AI->getArraySize())) {
|
||||||
|
unsigned BufferSize = TLI->getTargetMachine().Options.SSPBufferSize;
|
||||||
|
if (CI->getLimitedValue(BufferSize) >= BufferSize)
|
||||||
|
// A call to alloca with size >= SSPBufferSize requires
|
||||||
|
// stack protectors.
|
||||||
return true;
|
return true;
|
||||||
|
} else // A call to alloca with a variable size requires protectors.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ContainsProtectableArray(AI->getAllocatedType(), Strong))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (Strong && HasAddressTaken(AI)) {
|
||||||
|
++NumAddrTaken;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user