[llvm-commits] [llvm] r58673 - in /llvm/trunk: include/llvm/CodeGen/Passes.h lib/CodeGen/LLVMTargetMachine.cpp lib/CodeGen/StackProtector.cpp

Bill Wendling isanbard at gmail.com
Tue Nov 4 11:40:43 PST 2008


On Tue, Nov 4, 2008 at 5:28 AM, Chris Lattner <clattner at apple.com> wrote:
> On Nov 3, 2008, at 6:10 PM, Bill Wendling wrote:
>> URL: http://llvm.org/viewvc/llvm-project?rev=58673&view=rev
>> Log:
>> Initial checkin for stack protectors. Here's what it does:
>
> Cool!  Some questions/comments below:
>
>> @@ -60,6 +60,11 @@
>> EnableFastISelOption("fast-isel", cl::Hidden,
>>   cl::desc("Enable the experimental \"fast\" instruction selector"));
>>
>> +// Enable stack protectors.
>> +static cl::opt<int>
>> +EnableStackProtector("enable-stack-protector", cl::init(0),
>> +                     cl::desc("Use ProPolice as a stack protection
>> method."));
>
> I don't know what "ProPolice" is, but it sounds like it may be a
> trademark or something.  Please just use "stack canary" or something
> generic like that.
>
It's used in the GCC documentation for the flag:

common.opt:
fstack-protector
Common Report Var(flag_stack_protect, 1) Init(-1)
Use propolice as a stack protection method

But I can live without it.

> Also, you should use an enum for this, not magic integer numbers.  I'd
> like to see -enable-stack-protector=all | some | none.
>
Okay.

>> @@ -165,6 +170,8 @@
>>   if (!Fast)
>>     PM.add(createCodeGenPreparePass(getTargetLowering()));
>>
>> +  PM.add(createStackProtectorPass(EnableStackProtector));
>
> Why do you add the pass even when it is not enabled?  Have you looked
> at whether adding this pass ends up breaking analysis chains, and
> requiring them to be run multiple times?  For example, does dominators
> end up being run more frequently with this?  If so, the pass should
> update dominators instead of invalidating it.
>
Okay. No. Don't know.

>> +// random value in it is stored onto the stack before the local
>> variables are
>> +// allocated. Upon exitting the block, the stored value is checked.
>> If it's
>
> typo exiting.
>
>> +// Enable stack protectors.
>> +static cl::opt<unsigned>
>> +SSPBufferSize("ssp-buffer-size", cl::init(8),
>> +              cl::desc("The lower bound for a buffer to be
>> considered for "
>> +                       "stack smashing protection."));
>
> why the contraction ssp?  Please use something like "stack-protector-
> buffer-size" or something like that, for similarity with the enable-
> stack-protector option.
>
It's the same name that's used in GCC. I'm not tied to the name, and
I'm not expecting this to be used much at all.

>> +namespace {
>> +  class VISIBILITY_HIDDEN StackProtector : public FunctionPass {
>> +    // Level == 0  --  Stack protectors are off.
>> +    // Level == 1  --  Stack protectors are on only for some
>> functions.
>> +    // Level == 2  --  Stack protectors are on for all functions.
>> +    int Level;
>
> I think that this should be an enum in Passes.h, which can also be
> used above for the command line option.
>
Okay.

>>
>> ++    /// RequiresStackProtector - Check whether or not this
>> function needs a
>> +    /// stack protector based upon the stack protector level.
>> +    bool RequiresStackProtector();
>
> This should be const.
>
Oh yeah!

>> +/// InsertStackProtectorPrologue - Insert code into the entry block
>> that stores
>> +/// the __stack_chk_guard variable onto the stack.
>> +void StackProtector::InsertStackProtectorPrologue() {
>> +  BasicBlock &Entry = F->getEntryBlock();
>> +  Instruction &InsertPt = Entry.front();
>> +
>> +  const char *StackGuardStr = "__stack_chk_guard";
>> +  StackGuardVar = M->getNamedGlobal(StackGuardStr)
>
> If the module already has a '__stack_chk_guard' global with the wrong
> type, I think this code will crash, see below:
>
Hrh?

>>
>> +  if (!StackGuardVar)
>> +    StackGuardVar = new
>> GlobalVariable(PointerType::getUnqual(Type::Int8Ty),
>> +                                       false,
>> GlobalValue::ExternalLinkage,
>> +                                       0, StackGuardStr, M);
>
> We really want a Module::getOrInsertGlobal() method that works like
> getOrInsertFunction.  It would do the bitcast to solve the problem
> above and factor away this code.  Can you please add this?
>
Sure. That would be nice.

>> +  StackProtFrameSlot = new
>> AllocaInst(PointerType::getUnqual(Type::Int8Ty),
>> +                                      "StackProt_Frame", &InsertPt);
>
> What ensures that this alloca ends up in the right place in the stack
> frame at codegen time?
>
We looked at the code in code gen -- the lowering of allocas. It's
doing the "right thing" with regard to this. There might be some
special magic that needs to be done, though.

>> +  LoadInst *LI = new LoadInst(StackGuardVar, "StackGuard", true,
>> &InsertPt);
>> +  new StoreInst(LI, StackProtFrameSlot, true, &InsertPt);
>
> Please add a comment indicating why these are volatile.  Why is the
> load volatile?
>
This one probably doesn't need to be.

>> +/// InsertStackProtectorEpilogue - Insert code before the return
>> instructions
>> +/// checking the stack value that was stored in the prologue. If it
>> isn't the
>> +/// same as the original value, then call a "failure" function.
>> +void StackProtector::InsertStackProtectorEpilogue() {
>> +  // Create the basic block to jump to when the guard check fails.
>> +  CreateFailBB();
>> +
>> +  Function::iterator I = F->begin(), E = F->end();
>> +  std::vector<BasicBlock*> ReturnBBs;
>> +  ReturnBBs.reserve(F->size());
>> +
>> +  for (; I != E; ++I)
>> +    if (isa<ReturnInst>((*I).getTerminator()))
>> +      ReturnBBs.push_back(I);
>
> Two things: first, use I->getTerminator.  Second, why do you make a
> vector of returns and iterate over the vector?  You should be able to
> handle all of these with one pass over the function without the
> intermediate vector.  Also, F->size() is linear time, so that itself
> does a pass over the function.
>
I'm modifying the Function (inserting new blocks). Won't that
invalidate the iterators?

>> +  for (std::vector<BasicBlock*>::iterator
>> +         II = ReturnBBs.begin(), IE = ReturnBBs.end(); II != IE; +
>> +II) {
>> +    BasicBlock *BB = *II;
>> +    ReturnInst *RI = cast<ReturnInst>(BB->getTerminator());
>> +    Function::iterator InsPt = BB; ++InsPt; // Insertion point for
>> new BB.
>> +
>> +    BasicBlock *NewBB = BasicBlock::Create("SPRet", F, InsPt);
>> +
>> +    // Move the return instruction into the new basic block.
>> +    RI->removeFromParent();
>> +    NewBB->getInstList().insert(NewBB->begin(), RI);
>
> Please use BasicBlock::splitBasicBlock to simplify this code.
>
Okay.

>> +/// CreateFailBB - Create a basic block to jump to when the stack
>> protector
>> +/// check fails.
>> +void StackProtector::CreateFailBB() {
>> +  assert(!FailBB && "Failure basic block already created?!");
>> +  FailBB = BasicBlock::Create("CallStackCheckFailBlk", F);
>> +  std::vector<const Type*> Params;
>> +  Constant *StackChkFail =
>> +    M->getOrInsertFunction("__stack_chk_fail",
>> +                           FunctionType::get(Type::VoidTy, Params,
>> false));
>
> You can eliminate the temporary vector by using the varargs form of
> getOrInsertFunction:
>
> Constant *StackChkFail =
>   M->getOrInsertFunction("__stack_chk_fail", Type::VoidTy, NULL);
>
Ah! Good.

>> +/// RequiresStackProtector - Check whether or not this function
>> needs a stack
>> +/// protector based upon the stack protector level.
>> +bool StackProtector::RequiresStackProtector() {
>> +  switch (Level) {
>> +  default: return false;
>> +  case 2:  return true;
>> +  case 1: {
>
> Please use enums instead of magic numbers :)
>
But the magic makes it work!!! ;-)

>> +    // If the size of the local variables allocated on the stack is
>> greater than
>> +    // SSPBufferSize, then we require a stack protector.
>> +    uint64_t StackSize = 0;
>> +
>> +    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))
>> +          if (ConstantInt *CI = dyn_cast<ConstantInt>(AI-
>> >getArraySize())) {
>> +            const APInt &Size = CI->getValue();
>> +            StackSize += Size.getZExtValue() * 8;
>> +          }
>
> This isn't sufficient.  If you have "alloca i32", the array size is
> 1.  You need to use TargetData to multiply the array size by the size
> of the type.  Also, is the protection size in bits or bytes?
>
Bytes, so the "* 8" is wrong. I need to flesh this out some more.

> Does GCC ignore variable sized stack allocations?
>
>> +    if (SSPBufferSize <= StackSize)
>> +      return true;
>
> This check should be moved inside the loop so that you stop scanning a
> function as soon as you see at least enough to qualify for stack
> protection.
>
Okay.

>>
>> +
>> +// [EOF] StackProtector.cpp
>
> Urr?
>
Totally the end of file! ;-)

-bw



More information about the llvm-commits mailing list