llvm.org GIT mirror llvm / ed71bd2
[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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@294590 91177308-0d34-0410-b5e6-96231b3b80d8 David Bozier 3 years ago
4 changed file(s) with 160 addition(s) and 1 deletion(s). Raw diff Collapse all Expand all
1818
1919 #include "llvm/ADT/SmallPtrSet.h"
2020 #include "llvm/ADT/Triple.h"
21 #include "llvm/IR/DiagnosticInfo.h"
2122 #include "llvm/IR/Dominators.h"
2223 #include "llvm/IR/ValueMap.h"
2324 #include "llvm/Pass.h"
133134
134135 bool runOnFunction(Function &Fn) override;
135136 };
137
138 /// Diagnostic information for why SSP was applied.
139 class DiagnosticInfoSSP : public DiagnosticInfoWithDebugLocBase {
140 public:
141 enum SSPReason {
142 Alloca = 0,
143 BufferOrStruct = 1,
144 AddressTaken = 2,
145 Attribute = 3,
146 LastUsedValue = 3
147 };
148
149 /// \p Fn is the function where the diagnostic is being emitted. \p Reason is
150 /// an enum value representing why the function has stack protection.
151 DiagnosticInfoSSP(const Function &Fn, SSPReason Reason)
152 : DiagnosticInfoWithDebugLocBase(DK_SSPReason, DS_Remark, Fn, DebugLoc()),
153 Func(Fn), Why(Reason) {}
154
155 static bool classof(const DiagnosticInfo *DI) {
156 return DI->getKind() == DK_SSPReason;
157 }
158
159 void print(DiagnosticPrinter &DP) const override;
160
161 SSPReason Reason() const { return Why; }
162
163 private:
164 const Function &Func;
165 const SSPReason Why;
166 };
136167 } // end namespace llvm
137168
138169 #endif // LLVM_CODEGEN_STACKPROTECTOR_H
7676 DK_MIRParser,
7777 DK_PGOProfile,
7878 DK_Unsupported,
79 DK_SSPReason,
7980 DK_FirstPluginKind
8081 };
8182
2525 #include "llvm/IR/DataLayout.h"
2626 #include "llvm/IR/DebugInfo.h"
2727 #include "llvm/IR/DerivedTypes.h"
28 #include "llvm/IR/DiagnosticPrinter.h"
2829 #include "llvm/IR/Function.h"
2930 #include "llvm/IR/GlobalValue.h"
3031 #include "llvm/IR/GlobalVariable.h"
5051
5152 char StackProtector::ID = 0;
5253 INITIALIZE_TM_PASS(StackProtector, "stack-protector", "Insert stack protectors",
53 false, true)
54 false, true)
5455
5556 FunctionPass *llvm::createStackProtectorPass(const TargetMachine *TM) {
5657 return new StackProtector(TM);
222223 return false;
223224
224225 if (F->hasFnAttribute(Attribute::StackProtectReq)) {
226 F->getContext().diagnose(
227 DiagnosticInfoSSP(*F, DiagnosticInfoSSP::SSPReason::Attribute));
225228 NeedsProtector = true;
226229 Strong = true; // Use the same heuristic as strong to determine SSPLayout
227230 } else if (F->hasFnAttribute(Attribute::StackProtectStrong))
240243 // A call to alloca with size >= SSPBufferSize requires
241244 // stack protectors.
242245 Layout.insert(std::make_pair(AI, SSPLK_LargeArray));
246 F->getContext().diagnose(
247 DiagnosticInfoSSP(*F, DiagnosticInfoSSP::SSPReason::Alloca));
243248 NeedsProtector = true;
244249 } else if (Strong) {
245250 // Require protectors for all alloca calls in strong mode.
246251 Layout.insert(std::make_pair(AI, SSPLK_SmallArray));
252 F->getContext().diagnose(
253 DiagnosticInfoSSP(*F, DiagnosticInfoSSP::SSPReason::Alloca));
247254 NeedsProtector = true;
248255 }
249256 } else {
250257 // A call to alloca with a variable size requires protectors.
251258 Layout.insert(std::make_pair(AI, SSPLK_LargeArray));
259 F->getContext().diagnose(
260 DiagnosticInfoSSP(*F, DiagnosticInfoSSP::SSPReason::Alloca));
252261 NeedsProtector = true;
253262 }
254263 continue;
258267 if (ContainsProtectableArray(AI->getAllocatedType(), IsLarge, Strong)) {
259268 Layout.insert(std::make_pair(AI, IsLarge ? SSPLK_LargeArray
260269 : SSPLK_SmallArray));
270 F->getContext().diagnose(DiagnosticInfoSSP(
271 *F, DiagnosticInfoSSP::SSPReason::BufferOrStruct));
261272 NeedsProtector = true;
262273 continue;
263274 }
265276 if (Strong && HasAddressTaken(AI)) {
266277 ++NumAddrTaken;
267278 Layout.insert(std::make_pair(AI, SSPLK_AddrOf));
279 F->getContext().diagnose(DiagnosticInfoSSP(
280 *F, DiagnosticInfoSSP::SSPReason::AddressTaken));
268281 NeedsProtector = true;
269282 }
270283 }
463476 bool StackProtector::shouldEmitSDCheck(const BasicBlock &BB) const {
464477 return HasPrologue && !HasIRCheck && dyn_cast(BB.getTerminator());
465478 }
479
480 void DiagnosticInfoSSP::print(DiagnosticPrinter &DP) const {
481 std::string Str;
482 raw_string_ostream OS(Str);
483
484 StringRef ReasonStr;
485 switch (Reason())
486 {
487 case Alloca:
488 ReasonStr = "a call to alloca or use of a variable length array";
489 break;
490 case BufferOrStruct:
491 ReasonStr = "a stack allocated buffer or struct containing a buffer";
492 break;
493 case AddressTaken:
494 ReasonStr = "the address of a local variable being taken";
495 break;
496 case Attribute:
497 ReasonStr = "a function attribute or command-line switch";
498 break;
499 }
500
501 OS << getLocationStr() << ": SSP applied to function " << Func.getName()
502 << " due to " << ReasonStr << '\n';
503 OS.flush();
504 DP << Str;
505 }
0 ; RUN: llc %s -o /dev/null 2>&1 | FileCheck %s
1 ; CHECK-NOT: nossp
2 ; CHECK-NOT: alloca_fixed_small_nossp
3 ; CHECK: function attribute_ssp
4 ; CHECK-SAME: a function attribute or command-line switch
5 ; CHECK: function alloca_fixed_small_ssp
6 ; CHECK-SAME: a call to alloca or use of a variable length array
7 ; CHECK: function alloca_fixed_large_ssp
8 ; CHECK-SAME: a call to alloca or use of a variable length array
9 ; CHECK: function alloca_variable_ssp
10 ; CHECK-SAME: a call to alloca or use of a variable length array
11 ; CHECK: function buffer_ssp
12 ; CHECK-SAME: a stack allocated buffer or struct containing a buffer
13 ; CHECK: function struct_ssp
14 ; CHECK-SAME: a stack allocated buffer or struct containing a buffer
15 ; CHECK: function address_ssp
16 ; CHECK-SAME: the address of a local variable being taken
17 ; CHECK: function multiple_ssp
18 ; CHECK-SAME: a function attribute or command-line switch
19 ; CHECK: function multiple_ssp
20 ; CHECK-SAME: a stack allocated buffer or struct containing a buffer
21 ; CHECK: function multiple_ssp
22 ; CHECK-SAME: a stack allocated buffer or struct containing a buffer
23 ; CHECK: function multiple_ssp
24 ; CHECK-SAME: the address of a local variable being taken
25 ; CHECK: function multiple_ssp
26 ; CHECK-SAME: a call to alloca or use of a variable length array
27
28 define void @nossp() sspstrong {
29 ret void
30 }
31
32 define void @attribute_ssp() sspreq {
33 ret void
34 }
35
36 define void @alloca_fixed_small_nossp() ssp {
37 %1 = alloca i8, i64 2, align 16
38 ret void
39 }
40
41 define void @alloca_fixed_small_ssp() sspstrong {
42 %1 = alloca i8, i64 2, align 16
43 ret void
44 }
45
46 define void @alloca_fixed_large_ssp() ssp {
47 %1 = alloca i8, i64 64, align 16
48 ret void
49 }
50
51 define void @alloca_variable_ssp(i64 %x) ssp {
52 %1 = alloca i8, i64 %x, align 16
53 ret void
54 }
55
56 define void @buffer_ssp() sspstrong {
57 %x = alloca [64 x i32], align 16
58 ret void
59 }
60
61 %struct.X = type { [64 x i32] }
62 define void @struct_ssp() sspstrong {
63 %x = alloca %struct.X, align 4
64 ret void
65 }
66
67 define void @address_ssp() sspstrong {
68 entry:
69 %x = alloca i32, align 4
70 %y = alloca i32*, align 8
71 store i32 32, i32* %x, align 4
72 store i32* %x, i32** %y, align 8
73 ret void
74 }
75
76 define void @multiple_ssp() sspreq {
77 entry:
78 %x = alloca %struct.X, align 4
79 %y = alloca [64 x i32], align 16
80 %a = alloca i32, align 4
81 %b = alloca i32*, align 8
82 %0 = alloca i8, i64 2, align 16
83 store i32 32, i32* %a, align 4
84 store i32* %a, i32** %b, align 8
85 ret void
86 }