1 //===-- ASanStackFrameLayout.cpp - helper for AddressSanitizer ------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // Definition of ComputeASanStackFrameLayout (see ASanStackFrameLayout.h).
12 //===----------------------------------------------------------------------===//
13 #include "llvm/Transforms/Utils/ASanStackFrameLayout.h"
14 #include "llvm/ADT/SmallString.h"
15 #include "llvm/IR/DebugInfo.h"
16 #include "llvm/Support/MathExtras.h"
17 #include "llvm/Support/ScopedPrinter.h"
18 #include "llvm/Support/raw_ostream.h"
23 // We sort the stack variables by alignment (largest first) to minimize
24 // unnecessary large gaps due to alignment.
25 // It is tempting to also sort variables by size so that larger variables
26 // have larger redzones at both ends. But reordering will make report analysis
27 // harder, especially when temporary unnamed variables are present.
28 // So, until we can provide more information (type, line number, etc)
29 // for the stack variables we avoid reordering them too much.
30 static inline bool CompareVars(const ASanStackVariableDescription
&a
,
31 const ASanStackVariableDescription
&b
) {
32 return a
.Alignment
> b
.Alignment
;
35 // We also force minimal alignment for all vars to kMinAlignment so that vars
36 // with e.g. alignment 1 and alignment 16 do not get reordered by CompareVars.
37 static const size_t kMinAlignment
= 16;
39 // The larger the variable Size the larger is the redzone.
40 // The resulting frame size is a multiple of Alignment.
41 static size_t VarAndRedzoneSize(size_t Size
, size_t Alignment
) {
43 if (Size
<= 4) Res
= 16;
44 else if (Size
<= 16) Res
= 32;
45 else if (Size
<= 128) Res
= Size
+ 32;
46 else if (Size
<= 512) Res
= Size
+ 64;
47 else if (Size
<= 4096) Res
= Size
+ 128;
48 else Res
= Size
+ 256;
49 return alignTo(Res
, Alignment
);
53 ComputeASanStackFrameLayout(SmallVectorImpl
<ASanStackVariableDescription
> &Vars
,
54 size_t Granularity
, size_t MinHeaderSize
) {
55 assert(Granularity
>= 8 && Granularity
<= 64 &&
56 (Granularity
& (Granularity
- 1)) == 0);
57 assert(MinHeaderSize
>= 16 && (MinHeaderSize
& (MinHeaderSize
- 1)) == 0 &&
58 MinHeaderSize
>= Granularity
);
59 const size_t NumVars
= Vars
.size();
61 for (size_t i
= 0; i
< NumVars
; i
++)
62 Vars
[i
].Alignment
= std::max(Vars
[i
].Alignment
, kMinAlignment
);
64 std::stable_sort(Vars
.begin(), Vars
.end(), CompareVars
);
66 ASanStackFrameLayout Layout
;
67 Layout
.Granularity
= Granularity
;
68 Layout
.FrameAlignment
= std::max(Granularity
, Vars
[0].Alignment
);
69 size_t Offset
= std::max(std::max(MinHeaderSize
, Granularity
),
71 assert((Offset
% Granularity
) == 0);
72 for (size_t i
= 0; i
< NumVars
; i
++) {
73 bool IsLast
= i
== NumVars
- 1;
74 size_t Alignment
= std::max(Granularity
, Vars
[i
].Alignment
);
75 (void)Alignment
; // Used only in asserts.
76 size_t Size
= Vars
[i
].Size
;
77 assert((Alignment
& (Alignment
- 1)) == 0);
78 assert(Layout
.FrameAlignment
>= Alignment
);
79 assert((Offset
% Alignment
) == 0);
81 size_t NextAlignment
= IsLast
? Granularity
82 : std::max(Granularity
, Vars
[i
+ 1].Alignment
);
83 size_t SizeWithRedzone
= VarAndRedzoneSize(Size
, NextAlignment
);
84 Vars
[i
].Offset
= Offset
;
85 Offset
+= SizeWithRedzone
;
87 if (Offset
% MinHeaderSize
) {
88 Offset
+= MinHeaderSize
- (Offset
% MinHeaderSize
);
90 Layout
.FrameSize
= Offset
;
91 assert((Layout
.FrameSize
% MinHeaderSize
) == 0);
95 SmallString
<64> ComputeASanStackFrameDescription(
96 const SmallVectorImpl
<ASanStackVariableDescription
> &Vars
) {
97 SmallString
<2048> StackDescriptionStorage
;
98 raw_svector_ostream
StackDescription(StackDescriptionStorage
);
99 StackDescription
<< Vars
.size();
101 for (const auto &Var
: Vars
) {
102 std::string Name
= Var
.Name
;
105 Name
+= to_string(Var
.Line
);
107 StackDescription
<< " " << Var
.Offset
<< " " << Var
.Size
<< " "
108 << Name
.size() << " " << Name
;
110 return StackDescription
.str();
113 SmallVector
<uint8_t, 64>
114 GetShadowBytes(const SmallVectorImpl
<ASanStackVariableDescription
> &Vars
,
115 const ASanStackFrameLayout
&Layout
) {
116 assert(Vars
.size() > 0);
117 SmallVector
<uint8_t, 64> SB
;
119 const size_t Granularity
= Layout
.Granularity
;
120 SB
.resize(Vars
[0].Offset
/ Granularity
, kAsanStackLeftRedzoneMagic
);
121 for (const auto &Var
: Vars
) {
122 SB
.resize(Var
.Offset
/ Granularity
, kAsanStackMidRedzoneMagic
);
124 SB
.resize(SB
.size() + Var
.Size
/ Granularity
, 0);
125 if (Var
.Size
% Granularity
)
126 SB
.push_back(Var
.Size
% Granularity
);
128 SB
.resize(Layout
.FrameSize
/ Granularity
, kAsanStackRightRedzoneMagic
);
132 SmallVector
<uint8_t, 64> GetShadowBytesAfterScope(
133 const SmallVectorImpl
<ASanStackVariableDescription
> &Vars
,
134 const ASanStackFrameLayout
&Layout
) {
135 SmallVector
<uint8_t, 64> SB
= GetShadowBytes(Vars
, Layout
);
136 const size_t Granularity
= Layout
.Granularity
;
138 for (const auto &Var
: Vars
) {
139 assert(Var
.LifetimeSize
<= Var
.Size
);
140 const size_t LifetimeShadowSize
=
141 (Var
.LifetimeSize
+ Granularity
- 1) / Granularity
;
142 const size_t Offset
= Var
.Offset
/ Granularity
;
143 std::fill(SB
.begin() + Offset
, SB
.begin() + Offset
+ LifetimeShadowSize
,
144 kAsanStackUseAfterScopeMagic
);