StackProtector.cpp revision f7a0c7bf8bc8318ed28d889c9a56437ab3e91385
1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com//===-- StackProtector.cpp - Stack Protector Insertion --------------------===//
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com//
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com//                     The LLVM Compiler Infrastructure
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com//
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// This file is distributed under the University of Illinois Open Source
69d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org// License. See LICENSE.TXT for details.
79d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org//
89d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org//===----------------------------------------------------------------------===//
9fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org//
10d537341e16524d1e22ac5e6c8b9c8f274ba1833crobertphillips// This pass inserts stack protectors into functions which need them. A variable
1169cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com// with a random value in it is stored onto the stack before the local variables
129d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org// are allocated. Upon exiting the block, the stored value is checked. If it's
1381712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com// changed, then there was some sort of violation and the program aborts.
14b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com//
15fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org//===----------------------------------------------------------------------===//
16181e9bd9484ece4132e0cc5cfcff602134e5489dbsalomon@google.com
171878651990d7c9da72cf43481432232bbef3550dcommit-bot@chromium.org#define DEBUG_TYPE "stack-protector"
181878651990d7c9da72cf43481432232bbef3550dcommit-bot@chromium.org#include "llvm/CodeGen/Passes.h"
1981712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com#include "llvm/Attributes.h"
20181e9bd9484ece4132e0cc5cfcff602134e5489dbsalomon@google.com#include "llvm/Constants.h"
21181e9bd9484ece4132e0cc5cfcff602134e5489dbsalomon@google.com#include "llvm/DerivedTypes.h"
22383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com#include "llvm/Function.h"
23383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com#include "llvm/Instructions.h"
24383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com#include "llvm/Intrinsics.h"
25b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com#include "llvm/Module.h"
26383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com#include "llvm/Pass.h"
27383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com#include "llvm/Support/CommandLine.h"
28383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com#include "llvm/Target/TargetData.h"
29383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.com#include "llvm/Target/TargetLowering.h"
30383963280ddd13030331765fe88d2aefa3e32130bsalomon@google.comusing namespace llvm;
31181e9bd9484ece4132e0cc5cfcff602134e5489dbsalomon@google.com
3281712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com// SSPBufferSize - The lower bound for a buffer to be considered for stack
33181e9bd9484ece4132e0cc5cfcff602134e5489dbsalomon@google.com// smashing protection.
34181e9bd9484ece4132e0cc5cfcff602134e5489dbsalomon@google.comstatic cl::opt<unsigned>
35181e9bd9484ece4132e0cc5cfcff602134e5489dbsalomon@google.comSSPBufferSize("stack-protector-buffer-size", cl::init(8),
36b5b3168a645802f66233234a06dd5a3764f18018bsalomon@google.com              cl::desc("Lower bound for a buffer to be considered for "
374b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org                       "stack protection"));
389d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
39972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.orgnamespace {
4081712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com  class StackProtector : public FunctionPass {
41c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com    /// TLI - Keep a pointer of a TargetLowering to consult for determining
42afec7ba75962517b17293799d3fc70d39fa7dbf2tomhudson@google.com    /// target type sizes.
43c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com    const TargetLowering *TLI;
44f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org
45c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com    Function *F;
4681712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com    Module *M;
47c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com
489d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    /// InsertStackProtectors - Insert code into the prologue and epilogue of
499d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    /// the function.
509d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    ///
519d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    ///  - The prologue code loads and stores the stack guard onto the stack.
529d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    ///  - The epilogue checks the value stored in the prologue against the
539d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    ///    original value. It calls __stack_chk_fail if they differ.
54e1ca705cac4b946993f6cbf798e2a0ba27e739f3reed@google.com    bool InsertStackProtectors();
5561f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com
5661f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com    /// CreateFailBB - Create a basic block to jump to when the stack protector
5761f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com    /// check fails.
5861f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com    BasicBlock *CreateFailBB();
5961f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com
6061f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com    /// RequiresStackProtector - Check whether or not this function needs a
6161f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com    /// stack protector based upon the stack protector level.
62972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    bool RequiresStackProtector() const;
639d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  public:
649d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    static char ID;             // Pass identification, replacement for typeid.
659d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    StackProtector() : FunctionPass(&ID), TLI(0) {}
66972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    StackProtector(const TargetLowering *tli)
67972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org      : FunctionPass(&ID), TLI(tli) {}
68972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org
6981712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com    virtual bool runOnFunction(Function &Fn);
70972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org  };
71c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com} // end anonymous namespace
729d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
739d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.orgchar StackProtector::ID = 0;
749d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.orgstatic RegisterPass<StackProtector>
759d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.orgX("stack-protector", "Insert stack protectors");
769d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
779d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.orgFunctionPass *llvm::createStackProtectorPass(const TargetLowering *tli) {
789d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  return new StackProtector(tli);
79972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org}
8081712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com
8181712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.combool StackProtector::runOnFunction(Function &Fn) {
829d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  F = &Fn;
83972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org  M = F->getParent();
849d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
859d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  if (!RequiresStackProtector()) return false;
869d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
879d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  return InsertStackProtectors();
889d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org}
899d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
909d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org/// RequiresStackProtector - Check whether or not this function needs a stack
91972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org/// protector based upon the stack protector level. The heuristic we use is to
9281712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com/// add a guard variable to functions that call alloca, and functions with
93c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com/// buffers larger than SSPBufferSize bytes.
94afec7ba75962517b17293799d3fc70d39fa7dbf2tomhudson@google.combool StackProtector::RequiresStackProtector() const {
95c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com  if (F->hasFnAttr(Attribute::StackProtectReq))
96f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    return true;
97c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com
98972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org  if (!F->hasFnAttr(Attribute::StackProtect))
99c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com    return false;
100c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com
1012047f00e4698f83499ab91911999a65c21a951c9epoger@google.com  const TargetData *TD = TLI->getTargetData();
102c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com
1039d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  for (Function::iterator I = F->begin(), E = F->end(); I != E; ++I) {
1049d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    BasicBlock *BB = I;
105e1ca705cac4b946993f6cbf798e2a0ba27e739f3reed@google.com
10661f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com    for (BasicBlock::iterator
10761f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com           II = BB->begin(), IE = BB->end(); II != IE; ++II)
10861f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com      if (AllocaInst *AI = dyn_cast<AllocaInst>(II)) {
10961f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com        if (AI->isArrayAllocation())
11061f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com          // This is a call to alloca with a variable size. Emit stack
11161f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com          // protectors.
11261f3bde1ba114e7b39b53411f4aa31ed0875d159bsalomon@google.com          return true;
113972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org
1149d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        if (const ArrayType *AT = dyn_cast<ArrayType>(AI->getAllocatedType())) {
1159d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org          // We apparently only care about character arrays.
1169d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org          if (!AT->getElementType()->isIntegerTy(8))
117972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org            continue;
118972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org
119972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org          // If an array has more than SSPBufferSize bytes of allocated space,
120972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org          // then we emit stack protectors.
12181712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com          if (SSPBufferSize <= TD->getTypeAllocSize(AT))
122972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org            return true;
123c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com        }
1249d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org      }
1259d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  }
1269d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
1279d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  return false;
1289d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org}
1299d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
1309d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org/// InsertStackProtectors - Insert code into the prologue and epilogue of the
131972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org/// function.
13281712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com///
13381712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com///  - The prologue code loads and stores the stack guard onto the stack.
13481712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com///  - The epilogue checks the value stored in the prologue against the original
1359d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org///    value. It calls __stack_chk_fail if they differ.
136972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.orgbool StackProtector::InsertStackProtectors() {
13781712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com  BasicBlock *FailBB = 0;       // The basic block to jump to if check fails.
13881712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com  AllocaInst *AI = 0;           // Place on stack that stores the stack guard.
1399d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  Value *StackGuardVar = 0;  // The stack guard variable.
140972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org
1419d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org  for (Function::iterator I = F->begin(), E = F->end(); I != E; ) {
1429d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    BasicBlock *BB = I++;
1439d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
1449d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    ReturnInst *RI = dyn_cast<ReturnInst>(BB->getTerminator());
1459d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    if (!RI) continue;
1469d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
1478d033a1b125886c62906d975b5cc28a382064526bsalomon@google.com    if (!FailBB) {
14881712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com      // Insert code into the entry block that stores the __stack_chk_guard
149c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com      // variable onto the stack:
150afec7ba75962517b17293799d3fc70d39fa7dbf2tomhudson@google.com      //
151c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com      //   entry:
152f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org      //     StackGuardSlot = alloca i8*
153c10a88825d119054a9f4e7b7af7a3f887e30ab6btomhudson@google.com      //     StackGuard = load __stack_chk_guard
1549d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org      //     call void @llvm.stackprotect.create(StackGuard, StackGuardSlot)
1559d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org      //
1569d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org      PointerType *PtrTy = PointerType::getUnqual(
1579d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org          Type::getInt8Ty(RI->getContext()));
1589d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
159129b8e3237b80b9d258a8f48e8f54c0073cafbdcsenorblanco@chromium.org      unsigned AddressSpace, Offset;
16094b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com      if (TLI->getStackCookieLocation(AddressSpace, Offset)) {
1619d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        Constant *ASPtr = Constant::getNullValue(
162972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org            PointerType::get(Type::getInt8Ty(RI->getContext()), AddressSpace));
16394b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com        APInt OffsetInt(32, Offset);
1649d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        Constant *OffsetVal = Constant::getIntegerValue(
16594b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com            Type::getInt32Ty(RI->getContext()), OffsetInt);
16694b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com        StackGuardVar = ConstantExpr::getPointerCast(
1679d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org            ConstantExpr::getGetElementPtr(ASPtr, &OffsetVal, 1),
1689d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org            PointerType::get(PtrTy, AddressSpace));
16994b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com      } else {
1709d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org          StackGuardVar = M->getOrInsertGlobal("__stack_chk_guard", PtrTy);
1719d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org      }
17294b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com
1739d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org      BasicBlock &Entry = F->getEntryBlock();
1749d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org      Instruction *InsPt = &Entry.front();
17594b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com
1769d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org      AI = new AllocaInst(PtrTy, "StackGuardSlot", InsPt);
1779d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org      LoadInst *LI = new LoadInst(StackGuardVar, "StackGuard", false, InsPt);
1789d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
1799d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org      Value *Args[] = { LI, AI };
1809d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org      CallInst::
1819d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org        Create(Intrinsic::getDeclaration(M, Intrinsic::stackprotector),
1829d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org               &Args[0], array_endof(Args), "", InsPt);
1839d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
1849d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org      // Create the basic block to jump to when the guard check fails.
1859d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org      FailBB = CreateFailBB();
1869d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org    }
1879d18b7873ce9b44f130a41e0cbd0a3df76ab9adfsenorblanco@chromium.org
18869cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com    // For each block with a return instruction, convert this:
189972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org    //
1901971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com    //   return:
191dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com    //     ...
192dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com    //     ret ...
193dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com    //
194dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com    // into this:
195f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    //
196f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    //   return:
197f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    //     ...
198dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com    //     %1 = load __stack_chk_guard
199f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    //     %2 = load StackGuardSlot
200f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    //     %3 = cmp i1 %1, %2
201f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    //     br i1 %3, label %SP_return, label %CallStackCheckFailBlk
202f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    //
203f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    //   SP_return:
204f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    //     ret ...
205f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    //
206f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    //   CallStackCheckFailBlk:
207f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    //     call void @__stack_chk_fail()
208f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    //     unreachable
209f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org
2108491d24bdc3f48f67475c12c60babb9f9dba8047skia.committer@gmail.com    // Split the basic block before the return instruction.
211f543fd9e8c162b65fd04d1d9439b60911f8eb4c0commit-bot@chromium.org    BasicBlock *NewBB = BB->splitBasicBlock(RI, "SP_return");
212dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com
213dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com    // Remove default branch instruction to the new BB.
214dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com    BB->getTerminator()->eraseFromParent();
215dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com
216dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com    // Move the newly created basic block to the point right after the old basic
217dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com    // block so that it's in the "fall through" position.
218dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com    NewBB->moveAfter(BB);
219dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com
220dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com    // Generate the stack protector instructions in the old basic block.
221dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com    LoadInst *LI1 = new LoadInst(StackGuardVar, "", false, BB);
222dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com    LoadInst *LI2 = new LoadInst(AI, "", true, BB);
223dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com    ICmpInst *Cmp = new ICmpInst(*BB, CmpInst::ICMP_EQ, LI1, LI2, "");
224dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com    BranchInst::Create(NewBB, FailBB, Cmp, BB);
225dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com  }
226dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com
227dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com  // Return if we didn't modify any basic blocks. I.e., there are no return
228dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com  // statements in the function.
229972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org  if (!FailBB) return false;
23020e542e00eccaf7b9e81964692a47086e6aaf568bsalomon@google.com
23120e542e00eccaf7b9e81964692a47086e6aaf568bsalomon@google.com  return true;
23220e542e00eccaf7b9e81964692a47086e6aaf568bsalomon@google.com}
233972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org
234dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com/// CreateFailBB - Create a basic block to jump to when the stack protector
2351971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com/// check fails.
2361971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.comBasicBlock *StackProtector::CreateFailBB() {
2371971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com  BasicBlock *FailBB = BasicBlock::Create(F->getContext(),
2381971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com                                          "CallStackCheckFailBlk", F);
2391971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com  Constant *StackChkFail =
2401971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com    M->getOrInsertFunction("__stack_chk_fail",
2411971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com                           Type::getVoidTy(F->getContext()), NULL);
2421971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com  CallInst::Create(StackChkFail, "", FailBB);
243dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com  new UnreachableInst(F->getContext(), FailBB);
244dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com  return FailBB;
245dc3c78076ea279d4f6d502b3b42471e9b2bba48ebsalomon@google.com}
2461971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com