Pārlūkot izejas kodu

[stackprotector] Update the StackProtector pass to perform datalayout analysis.

This modifies the pass to classify every SSP-triggering AllocaInst according to
an SSPLayoutKind (LargeArray, SmallArray, AddrOf).  This analysis is collected
by the pass and made available for use, but no other pass uses it yet.

The next patch will make use of this analysis in PEI and StackSlot
passes.  The end goal is to support ssp-strong stack layout rules.

WIP.

Differential Revision: http://llvm-reviews.chandlerc.com/D1789


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@193653 91177308-0d34-0410-b5e6-96231b3b80d8
Josh Magee 11 gadi atpakaļ
vecāks
revīzija
4598b40ce6
2 mainītis faili ar 90 papildinājumiem un 28 dzēšanām
  1. 30 1
      include/llvm/CodeGen/StackProtector.h
  2. 60 27
      lib/CodeGen/StackProtector.cpp

+ 30 - 1
include/llvm/CodeGen/StackProtector.h

@@ -19,6 +19,7 @@
 
 
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/Triple.h"
 #include "llvm/ADT/Triple.h"
+#include "llvm/ADT/ValueMap.h"
 #include "llvm/Pass.h"
 #include "llvm/Pass.h"
 #include "llvm/Target/TargetLowering.h"
 #include "llvm/Target/TargetLowering.h"
 
 
@@ -29,6 +30,24 @@ class Module;
 class PHINode;
 class PHINode;
 
 
 class StackProtector : public FunctionPass {
 class StackProtector : public FunctionPass {
+public:
+  /// SSPLayoutKind.  Stack Smashing Protection (SSP) rules require that 
+  /// vulnerable stack allocations are located close the stack protector.
+  enum SSPLayoutKind {
+    SSPLK_None,       //< Did not trigger a stack protector.  No effect on data
+                      //< layout.
+    SSPLK_LargeArray, //< Array or nested array >= SSP-buffer-size.  Closest
+                      //< to the stack protector.
+    SSPLK_SmallArray, //< Array or nested array < SSP-buffer-size. 2nd closest
+                      //< to the stack protector.
+    SSPLK_AddrOf      //< The address of this allocation is exposed and
+                      //< triggered protection.  3rd closest to the protector.
+  };
+
+  /// A mapping of AllocaInsts to their required SSP layout.
+  typedef ValueMap<const AllocaInst*, SSPLayoutKind> SSPLayoutMap;
+
+private:
   const TargetMachine *TM;
   const TargetMachine *TM;
 
 
   /// TLI - Keep a pointer of a TargetLowering to consult for determining
   /// TLI - Keep a pointer of a TargetLowering to consult for determining
@@ -41,6 +60,11 @@ class StackProtector : public FunctionPass {
 
 
   DominatorTree *DT;
   DominatorTree *DT;
 
 
+  /// Layout - Mapping of allocations to the required SSPLayoutKind.
+  /// StackProtector analysis will update this map when determining if an
+  /// AllocaInst triggers a stack protector.
+  SSPLayoutMap Layout;
+
   /// \brief The minimum size of buffers that will receive stack smashing
   /// \brief The minimum size of buffers that will receive stack smashing
   /// protection when -fstack-protection is used.
   /// protection when -fstack-protection is used.
   unsigned SSPBufferSize;
   unsigned SSPBufferSize;
@@ -66,7 +90,10 @@ class StackProtector : public FunctionPass {
   /// 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 Strong = false,
+  /// \param [out] IsLarge is set to true if a protectable array is found and
+  /// it is "large" ( >= ssp-buffer-size).  In the case of a structure with
+  /// multiple arrays, this gets set if any of them is large.
+  bool ContainsProtectableArray(Type *Ty, bool &IsLarge, bool Strong = false,
                                 bool InStruct = false) const;
                                 bool InStruct = false) const;
 
 
   /// \brief Check whether a stack allocation has its address taken.
   /// \brief Check whether a stack allocation has its address taken.
@@ -90,6 +117,8 @@ public:
     AU.addPreserved<DominatorTree>();
     AU.addPreserved<DominatorTree>();
   }
   }
 
 
+  SSPLayoutKind getSSPLayout(const AllocaInst *AI) const;
+
   virtual bool runOnFunction(Function &Fn);
   virtual bool runOnFunction(Function &Fn);
 };
 };
 } // end namespace llvm
 } // end namespace llvm

+ 60 - 27
lib/CodeGen/StackProtector.cpp

@@ -48,12 +48,17 @@ EnableSelectionDAGSP("enable-selectiondag-sp", cl::init(true),
 
 
 char StackProtector::ID = 0;
 char StackProtector::ID = 0;
 INITIALIZE_PASS(StackProtector, "stack-protector",
 INITIALIZE_PASS(StackProtector, "stack-protector",
-                "Insert stack protectors", false, false)
+                "Insert stack protectors", false, true)
 
 
 FunctionPass *llvm::createStackProtectorPass(const TargetMachine *TM) {
 FunctionPass *llvm::createStackProtectorPass(const TargetMachine *TM) {
   return new StackProtector(TM);
   return new StackProtector(TM);
 }
 }
 
 
+StackProtector::SSPLayoutKind StackProtector::getSSPLayout(const AllocaInst *AI)
+                                                           const {
+  return AI ? Layout.lookup(AI) : SSPLK_None;
+}
+
 bool StackProtector::runOnFunction(Function &Fn) {
 bool StackProtector::runOnFunction(Function &Fn) {
   F = &Fn;
   F = &Fn;
   M = F->getParent();
   M = F->getParent();
@@ -72,39 +77,51 @@ bool StackProtector::runOnFunction(Function &Fn) {
   return InsertStackProtectors();
   return InsertStackProtectors();
 }
 }
 
 
-/// ContainsProtectableArray - Check whether the type either is an array or
-/// contains a char array of sufficient size so that we need stack protectors
-/// for it.
-bool StackProtector::ContainsProtectableArray(Type *Ty, bool Strong,
-                                              bool InStruct) const {
+/// \param [out] IsLarge is set to true if a protectable array is found and
+/// it is "large" ( >= ssp-buffer-size).  In the case of a structure with
+/// multiple arrays, this gets set if any of them is large.
+bool StackProtector::ContainsProtectableArray(Type *Ty, bool &IsLarge,
+                                              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;
     if (!AT->getElementType()->isIntegerTy(8)) {
     if (!AT->getElementType()->isIntegerTy(8)) {
       // If we're on a non-Darwin platform or we're inside of a structure, don't
       // If we're on a non-Darwin platform or we're inside of a structure, don't
       // add stack protectors unless the array is a character array.
       // add stack protectors unless the array is a character array.
-      if (InStruct || !Trip.isOSDarwin())
-          return false;
+      // However, in strong mode any array, regardless of type and size,
+      // triggers a protector.
+      if (!Strong && (InStruct || !Trip.isOSDarwin()))
+        return false;
     }
     }
 
 
     // If an array has more than SSPBufferSize bytes of allocated space, then we
     // If an array has more than SSPBufferSize bytes of allocated space, then we
     // emit stack protectors.
     // emit stack protectors.
-    if (SSPBufferSize <= TLI->getDataLayout()->getTypeAllocSize(AT))
+    if (SSPBufferSize <= TLI->getDataLayout()->getTypeAllocSize(AT)) {
+      IsLarge = true;
+      return true;
+    } 
+
+    if (Strong)
+      // Require a protector for all arrays in strong mode
       return true;
       return true;
   }
   }
 
 
   const StructType *ST = dyn_cast<StructType>(Ty);
   const StructType *ST = dyn_cast<StructType>(Ty);
   if (!ST) return false;
   if (!ST) return false;
 
 
+  bool NeedsProtector = false;
   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, Strong, true))
-      return true;
+    if (ContainsProtectableArray(*I, IsLarge, Strong, true)) {
+      // If the element is a protectable array and is large (>= SSPBufferSize)
+      // then we are done.  If the protectable array is not large, then
+      // keep looking in case a subsequent element is a large array.
+      if (IsLarge)
+        return true;
+      NeedsProtector = true;
+    }
 
 
-  return false;
+  return NeedsProtector;
 }
 }
 
 
 bool StackProtector::HasAddressTaken(const Instruction *AI) {
 bool StackProtector::HasAddressTaken(const Instruction *AI) {
@@ -156,11 +173,13 @@ bool StackProtector::HasAddressTaken(const Instruction *AI) {
 /// address taken.
 /// address taken.
 bool StackProtector::RequiresStackProtector() {
 bool StackProtector::RequiresStackProtector() {
   bool Strong = false;
   bool Strong = false;
+  bool NeedsProtector = false;
   if (F->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
   if (F->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
-                                      Attribute::StackProtectReq))
-    return true;
-  else if (F->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
-                                           Attribute::StackProtectStrong))
+                                      Attribute::StackProtectReq)) {
+    NeedsProtector = true;
+    Strong = true; // Use the same heuristic as strong to determine SSPLayout
+  } else if (F->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
+                                             Attribute::StackProtectStrong))
     Strong = true;
     Strong = true;
   else if (!F->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
   else if (!F->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
                                             Attribute::StackProtect))
                                             Attribute::StackProtect))
@@ -180,28 +199,42 @@ bool StackProtector::RequiresStackProtector() {
 
 
           if (const ConstantInt *CI =
           if (const ConstantInt *CI =
                dyn_cast<ConstantInt>(AI->getArraySize())) {
                dyn_cast<ConstantInt>(AI->getArraySize())) {
-            if (CI->getLimitedValue(SSPBufferSize) >= SSPBufferSize)
+            if (CI->getLimitedValue(SSPBufferSize) >= SSPBufferSize) {
               // A call to alloca with size >= SSPBufferSize requires
               // A call to alloca with size >= SSPBufferSize requires
               // stack protectors.
               // stack protectors.
-              return true;
+              Layout.insert(std::make_pair(AI, SSPLK_LargeArray));
+              NeedsProtector = true;
+            } else if (Strong) {
+              // Require protectors for all alloca calls in strong mode.
+              Layout.insert(std::make_pair(AI, SSPLK_SmallArray));
+              NeedsProtector = true;
+            }
           } else {
           } else {
             // A call to alloca with a variable size requires protectors.
             // A call to alloca with a variable size requires protectors.
-            return true;
+            Layout.insert(std::make_pair(AI, SSPLK_LargeArray));
+            NeedsProtector = true;
           }
           }
+          continue;
         }
         }
 
 
-        if (ContainsProtectableArray(AI->getAllocatedType(), Strong))
-          return true;
+        bool IsLarge = false;
+        if (ContainsProtectableArray(AI->getAllocatedType(), IsLarge, Strong)) {
+          Layout.insert(std::make_pair(AI, IsLarge ? SSPLK_LargeArray
+                                                   : SSPLK_SmallArray));
+          NeedsProtector = true;
+          continue;
+        }
 
 
         if (Strong && HasAddressTaken(AI)) {
         if (Strong && HasAddressTaken(AI)) {
           ++NumAddrTaken;
           ++NumAddrTaken;
-          return true;
+          Layout.insert(std::make_pair(AI, SSPLK_AddrOf));
+          NeedsProtector = true;
         }
         }
       }
       }
     }
     }
   }
   }
 
 
-  return false;
+  return NeedsProtector;
 }
 }
 
 
 static bool InstructionWillNotHaveChain(const Instruction *I) {
 static bool InstructionWillNotHaveChain(const Instruction *I) {