[llvm] r294590 - [Stack Protection] Add diagnostic information for why stack protection was applied to a function

David Bozier via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 9 07:08:41 PST 2017


Author: davidb
Date: Thu Feb  9 09:08:40 2017
New Revision: 294590

URL: http://llvm.org/viewvc/llvm-project?rev=294590&view=rev
Log:
[Stack Protection] Add diagnostic information for why stack protection was applied to a function

Stack Smash Protection is not completely free, so in hot code, the overhead it causes can cause performance issues. By adding diagnostic information for which function have SSP and why, a user can quickly determine what they can do to stop SSP being applied to a specific hot function.

This change adds an SSP-specific DiagnosticInfo class and uses of it to the Stack Protection code. A subsequent change to clang will cause the remarks to be emitted when enabled.

Patch by: James Henderson

Differential Revision: https://reviews.llvm.org/D29023


Added:
    llvm/trunk/test/CodeGen/X86/stack-protector-remarks.ll
Modified:
    llvm/trunk/include/llvm/CodeGen/StackProtector.h
    llvm/trunk/include/llvm/IR/DiagnosticInfo.h
    llvm/trunk/lib/CodeGen/StackProtector.cpp

Modified: llvm/trunk/include/llvm/CodeGen/StackProtector.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/StackProtector.h?rev=294590&r1=294589&r2=294590&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/StackProtector.h (original)
+++ llvm/trunk/include/llvm/CodeGen/StackProtector.h Thu Feb  9 09:08:40 2017
@@ -19,6 +19,7 @@
 
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/Triple.h"
+#include "llvm/IR/DiagnosticInfo.h"
 #include "llvm/IR/Dominators.h"
 #include "llvm/IR/ValueMap.h"
 #include "llvm/Pass.h"
@@ -134,6 +135,36 @@ public:
 
   bool runOnFunction(Function &Fn) override;
 };
+
+/// Diagnostic information for why SSP was applied.
+class DiagnosticInfoSSP : public DiagnosticInfoWithDebugLocBase {
+public:
+  enum SSPReason {
+    Alloca = 0,
+    BufferOrStruct = 1,
+    AddressTaken = 2,
+    Attribute = 3,
+    LastUsedValue = 3
+  };
+
+  /// \p Fn is the function where the diagnostic is being emitted. \p Reason is
+  /// an enum value representing why the function has stack protection.
+  DiagnosticInfoSSP(const Function &Fn, SSPReason Reason)
+      : DiagnosticInfoWithDebugLocBase(DK_SSPReason, DS_Remark, Fn, DebugLoc()),
+        Func(Fn), Why(Reason) {}
+
+  static bool classof(const DiagnosticInfo *DI) {
+    return DI->getKind() == DK_SSPReason;
+  }
+
+  void print(DiagnosticPrinter &DP) const override;
+
+  SSPReason Reason() const { return Why; }
+
+private:
+  const Function &Func;
+  const SSPReason Why;
+};
 } // end namespace llvm
 
 #endif // LLVM_CODEGEN_STACKPROTECTOR_H

Modified: llvm/trunk/include/llvm/IR/DiagnosticInfo.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/DiagnosticInfo.h?rev=294590&r1=294589&r2=294590&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/DiagnosticInfo.h (original)
+++ llvm/trunk/include/llvm/IR/DiagnosticInfo.h Thu Feb  9 09:08:40 2017
@@ -77,6 +77,7 @@ enum DiagnosticKind {
   DK_MIRParser,
   DK_PGOProfile,
   DK_Unsupported,
+  DK_SSPReason,
   DK_FirstPluginKind
 };
 

Modified: llvm/trunk/lib/CodeGen/StackProtector.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/StackProtector.cpp?rev=294590&r1=294589&r2=294590&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/StackProtector.cpp (original)
+++ llvm/trunk/lib/CodeGen/StackProtector.cpp Thu Feb  9 09:08:40 2017
@@ -26,6 +26,7 @@
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/DebugInfo.h"
 #include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/DiagnosticPrinter.h"
 #include "llvm/IR/Function.h"
 #include "llvm/IR/GlobalValue.h"
 #include "llvm/IR/GlobalVariable.h"
@@ -51,7 +52,7 @@ static cl::opt<bool> EnableSelectionDAGS
 
 char StackProtector::ID = 0;
 INITIALIZE_TM_PASS(StackProtector, "stack-protector", "Insert stack protectors",
-                false, true)
+                   false, true)
 
 FunctionPass *llvm::createStackProtectorPass(const TargetMachine *TM) {
   return new StackProtector(TM);
@@ -223,6 +224,8 @@ bool StackProtector::RequiresStackProtec
     return false;
 
   if (F->hasFnAttribute(Attribute::StackProtectReq)) {
+    F->getContext().diagnose(
+        DiagnosticInfoSSP(*F, DiagnosticInfoSSP::SSPReason::Attribute));
     NeedsProtector = true;
     Strong = true; // Use the same heuristic as strong to determine SSPLayout
   } else if (F->hasFnAttribute(Attribute::StackProtectStrong))
@@ -241,15 +244,21 @@ bool StackProtector::RequiresStackProtec
               // A call to alloca with size >= SSPBufferSize requires
               // stack protectors.
               Layout.insert(std::make_pair(AI, SSPLK_LargeArray));
+              F->getContext().diagnose(
+                  DiagnosticInfoSSP(*F, DiagnosticInfoSSP::SSPReason::Alloca));
               NeedsProtector = true;
             } else if (Strong) {
               // Require protectors for all alloca calls in strong mode.
               Layout.insert(std::make_pair(AI, SSPLK_SmallArray));
+              F->getContext().diagnose(
+                  DiagnosticInfoSSP(*F, DiagnosticInfoSSP::SSPReason::Alloca));
               NeedsProtector = true;
             }
           } else {
             // A call to alloca with a variable size requires protectors.
             Layout.insert(std::make_pair(AI, SSPLK_LargeArray));
+            F->getContext().diagnose(
+                DiagnosticInfoSSP(*F, DiagnosticInfoSSP::SSPReason::Alloca));
             NeedsProtector = true;
           }
           continue;
@@ -259,6 +268,8 @@ bool StackProtector::RequiresStackProtec
         if (ContainsProtectableArray(AI->getAllocatedType(), IsLarge, Strong)) {
           Layout.insert(std::make_pair(AI, IsLarge ? SSPLK_LargeArray
                                                    : SSPLK_SmallArray));
+          F->getContext().diagnose(DiagnosticInfoSSP(
+              *F, DiagnosticInfoSSP::SSPReason::BufferOrStruct));
           NeedsProtector = true;
           continue;
         }
@@ -266,6 +277,8 @@ bool StackProtector::RequiresStackProtec
         if (Strong && HasAddressTaken(AI)) {
           ++NumAddrTaken;
           Layout.insert(std::make_pair(AI, SSPLK_AddrOf));
+          F->getContext().diagnose(DiagnosticInfoSSP(
+              *F, DiagnosticInfoSSP::SSPReason::AddressTaken));
           NeedsProtector = true;
         }
       }
@@ -464,3 +477,30 @@ BasicBlock *StackProtector::CreateFailBB
 bool StackProtector::shouldEmitSDCheck(const BasicBlock &BB) const {
   return HasPrologue && !HasIRCheck && dyn_cast<ReturnInst>(BB.getTerminator());
 }
+
+void DiagnosticInfoSSP::print(DiagnosticPrinter &DP) const {
+  std::string Str;
+  raw_string_ostream OS(Str);
+
+  StringRef ReasonStr;
+  switch (Reason())
+  {
+  case Alloca:
+      ReasonStr = "a call to alloca or use of a variable length array";
+      break;
+  case BufferOrStruct:
+      ReasonStr = "a stack allocated buffer or struct containing a buffer";
+      break;
+  case AddressTaken:
+      ReasonStr = "the address of a local variable being taken";
+      break;
+  case Attribute:
+      ReasonStr = "a function attribute or command-line switch";
+      break;
+  }
+
+  OS << getLocationStr() << ": SSP applied to function " << Func.getName()
+     << " due to " << ReasonStr << '\n';
+  OS.flush();
+  DP << Str;
+}

Added: llvm/trunk/test/CodeGen/X86/stack-protector-remarks.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/stack-protector-remarks.ll?rev=294590&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/X86/stack-protector-remarks.ll (added)
+++ llvm/trunk/test/CodeGen/X86/stack-protector-remarks.ll Thu Feb  9 09:08:40 2017
@@ -0,0 +1,87 @@
+; RUN: llc %s -o /dev/null 2>&1 | FileCheck %s
+; CHECK-NOT: nossp
+; CHECK-NOT: alloca_fixed_small_nossp
+; CHECK: function attribute_ssp
+; CHECK-SAME: a function attribute or command-line switch
+; CHECK: function alloca_fixed_small_ssp
+; CHECK-SAME: a call to alloca or use of a variable length array
+; CHECK: function alloca_fixed_large_ssp
+; CHECK-SAME: a call to alloca or use of a variable length array
+; CHECK: function alloca_variable_ssp
+; CHECK-SAME: a call to alloca or use of a variable length array
+; CHECK: function buffer_ssp
+; CHECK-SAME: a stack allocated buffer or struct containing a buffer
+; CHECK: function struct_ssp
+; CHECK-SAME: a stack allocated buffer or struct containing a buffer
+; CHECK: function address_ssp
+; CHECK-SAME: the address of a local variable being taken
+; CHECK: function multiple_ssp
+; CHECK-SAME: a function attribute or command-line switch
+; CHECK: function multiple_ssp
+; CHECK-SAME: a stack allocated buffer or struct containing a buffer
+; CHECK: function multiple_ssp
+; CHECK-SAME: a stack allocated buffer or struct containing a buffer
+; CHECK: function multiple_ssp
+; CHECK-SAME: the address of a local variable being taken
+; CHECK: function multiple_ssp
+; CHECK-SAME: a call to alloca or use of a variable length array
+
+define void @nossp() sspstrong {
+    ret void
+}
+
+define void @attribute_ssp() sspreq {
+  ret void
+}
+
+define void @alloca_fixed_small_nossp() ssp {
+  %1 = alloca i8, i64 2, align 16
+  ret void
+}
+
+define void @alloca_fixed_small_ssp() sspstrong {
+  %1 = alloca i8, i64 2, align 16
+  ret void
+}
+
+define void @alloca_fixed_large_ssp() ssp {
+  %1 = alloca i8, i64 64, align 16
+  ret void
+}
+
+define void @alloca_variable_ssp(i64 %x) ssp {
+  %1 = alloca i8, i64 %x, align 16
+  ret void
+}
+
+define void @buffer_ssp() sspstrong {
+  %x = alloca [64 x i32], align 16
+  ret void
+}
+
+%struct.X = type { [64 x i32] }
+define void @struct_ssp() sspstrong {
+  %x = alloca %struct.X, align 4
+  ret void
+}
+
+define void @address_ssp() sspstrong {
+entry:
+  %x = alloca i32, align 4
+  %y = alloca i32*, align 8
+  store i32 32, i32* %x, align 4
+  store i32* %x, i32** %y, align 8
+  ret void
+}
+
+define void @multiple_ssp() sspreq {
+entry:
+  %x = alloca %struct.X, align 4
+  %y = alloca [64 x i32], align 16
+  %a = alloca i32, align 4
+  %b = alloca i32*, align 8
+  %0 = alloca i8, i64 2, align 16
+  store i32 32, i32* %a, align 4
+  store i32* %a, i32** %b, align 8
+  ret void
+}




More information about the llvm-commits mailing list