]>
Commit | Line | Data |
---|---|---|
23e39437 | 1 | //===-- asan_descriptions.h -------------------------------------*- C++ -*-===// |
2 | // | |
3 | // This file is distributed under the University of Illinois Open Source | |
4 | // License. See LICENSE.TXT for details. | |
5 | // | |
6 | //===----------------------------------------------------------------------===// | |
7 | // | |
8 | // This file is a part of AddressSanitizer, an address sanity checker. | |
9 | // | |
10 | // ASan-private header for asan_descriptions.cc. | |
11 | // TODO(filcab): Most struct definitions should move to the interface headers. | |
12 | //===----------------------------------------------------------------------===// | |
13 | #ifndef ASAN_DESCRIPTIONS_H | |
14 | #define ASAN_DESCRIPTIONS_H | |
15 | ||
16 | #include "asan_allocator.h" | |
17 | #include "asan_thread.h" | |
18 | #include "sanitizer_common/sanitizer_common.h" | |
19 | #include "sanitizer_common/sanitizer_report_decorator.h" | |
20 | ||
21 | namespace __asan { | |
22 | ||
23 | void DescribeThread(AsanThreadContext *context); | |
24 | static inline void DescribeThread(AsanThread *t) { | |
25 | if (t) DescribeThread(t->context()); | |
26 | } | |
27 | const char *ThreadNameWithParenthesis(AsanThreadContext *t, char buff[], | |
28 | uptr buff_len); | |
29 | const char *ThreadNameWithParenthesis(u32 tid, char buff[], uptr buff_len); | |
30 | ||
31 | class Decorator : public __sanitizer::SanitizerCommonDecorator { | |
32 | public: | |
33 | Decorator() : SanitizerCommonDecorator() {} | |
34 | const char *Access() { return Blue(); } | |
23e39437 | 35 | const char *Location() { return Green(); } |
23e39437 | 36 | const char *Allocation() { return Magenta(); } |
23e39437 | 37 | |
38 | const char *ShadowByte(u8 byte) { | |
39 | switch (byte) { | |
40 | case kAsanHeapLeftRedzoneMagic: | |
41 | case kAsanArrayCookieMagic: | |
42 | return Red(); | |
43 | case kAsanHeapFreeMagic: | |
44 | return Magenta(); | |
45 | case kAsanStackLeftRedzoneMagic: | |
46 | case kAsanStackMidRedzoneMagic: | |
47 | case kAsanStackRightRedzoneMagic: | |
48 | return Red(); | |
49 | case kAsanStackAfterReturnMagic: | |
50 | return Magenta(); | |
51 | case kAsanInitializationOrderMagic: | |
52 | return Cyan(); | |
53 | case kAsanUserPoisonedMemoryMagic: | |
54 | case kAsanContiguousContainerOOBMagic: | |
55 | case kAsanAllocaLeftMagic: | |
56 | case kAsanAllocaRightMagic: | |
57 | return Blue(); | |
58 | case kAsanStackUseAfterScopeMagic: | |
59 | return Magenta(); | |
60 | case kAsanGlobalRedzoneMagic: | |
61 | return Red(); | |
62 | case kAsanInternalHeapMagic: | |
63 | return Yellow(); | |
64 | case kAsanIntraObjectRedzone: | |
65 | return Yellow(); | |
66 | default: | |
67 | return Default(); | |
68 | } | |
69 | } | |
23e39437 | 70 | }; |
71 | ||
72 | enum ShadowKind : u8 { | |
73 | kShadowKindLow, | |
74 | kShadowKindGap, | |
75 | kShadowKindHigh, | |
76 | }; | |
77 | static const char *const ShadowNames[] = {"low shadow", "shadow gap", | |
78 | "high shadow"}; | |
79 | ||
80 | struct ShadowAddressDescription { | |
81 | uptr addr; | |
82 | ShadowKind kind; | |
83 | u8 shadow_byte; | |
84 | ||
85 | void Print() const; | |
86 | }; | |
87 | ||
88 | bool GetShadowAddressInformation(uptr addr, ShadowAddressDescription *descr); | |
89 | bool DescribeAddressIfShadow(uptr addr); | |
90 | ||
91 | enum AccessType { | |
92 | kAccessTypeLeft, | |
93 | kAccessTypeRight, | |
94 | kAccessTypeInside, | |
95 | kAccessTypeUnknown, // This means we have an AddressSanitizer bug! | |
96 | }; | |
97 | ||
98 | struct ChunkAccess { | |
99 | uptr bad_addr; | |
100 | sptr offset; | |
101 | uptr chunk_begin; | |
102 | uptr chunk_size; | |
103 | u32 access_type : 2; | |
104 | u32 alloc_type : 2; | |
105 | }; | |
106 | ||
107 | struct HeapAddressDescription { | |
108 | uptr addr; | |
109 | uptr alloc_tid; | |
110 | uptr free_tid; | |
111 | u32 alloc_stack_id; | |
112 | u32 free_stack_id; | |
113 | ChunkAccess chunk_access; | |
114 | ||
115 | void Print() const; | |
116 | }; | |
117 | ||
118 | bool GetHeapAddressInformation(uptr addr, uptr access_size, | |
119 | HeapAddressDescription *descr); | |
120 | bool DescribeAddressIfHeap(uptr addr, uptr access_size = 1); | |
121 | ||
122 | struct StackAddressDescription { | |
123 | uptr addr; | |
124 | uptr tid; | |
125 | uptr offset; | |
126 | uptr frame_pc; | |
127 | uptr access_size; | |
128 | const char *frame_descr; | |
129 | ||
130 | void Print() const; | |
131 | }; | |
132 | ||
133 | bool GetStackAddressInformation(uptr addr, uptr access_size, | |
134 | StackAddressDescription *descr); | |
135 | ||
136 | struct GlobalAddressDescription { | |
137 | uptr addr; | |
138 | // Assume address is close to at most four globals. | |
139 | static const int kMaxGlobals = 4; | |
140 | __asan_global globals[kMaxGlobals]; | |
141 | u32 reg_sites[kMaxGlobals]; | |
142 | uptr access_size; | |
143 | u8 size; | |
144 | ||
145 | void Print(const char *bug_type = "") const; | |
eabe2d94 | 146 | |
147 | // Returns true when this descriptions points inside the same global variable | |
148 | // as other. Descriptions can have different address within the variable | |
149 | bool PointsInsideTheSameVariable(const GlobalAddressDescription &other) const; | |
23e39437 | 150 | }; |
151 | ||
152 | bool GetGlobalAddressInformation(uptr addr, uptr access_size, | |
153 | GlobalAddressDescription *descr); | |
154 | bool DescribeAddressIfGlobal(uptr addr, uptr access_size, const char *bug_type); | |
155 | ||
156 | // General function to describe an address. Will try to describe the address as | |
157 | // a shadow, global (variable), stack, or heap address. | |
158 | // bug_type is optional and is used for checking if we're reporting an | |
159 | // initialization-order-fiasco | |
160 | // The proper access_size should be passed for stack, global, and heap | |
161 | // addresses. Defaults to 1. | |
162 | // Each of the *AddressDescription functions has its own Print() member, which | |
163 | // may take access_size and bug_type parameters if needed. | |
164 | void PrintAddressDescription(uptr addr, uptr access_size = 1, | |
165 | const char *bug_type = ""); | |
166 | ||
167 | enum AddressKind { | |
168 | kAddressKindWild, | |
169 | kAddressKindShadow, | |
170 | kAddressKindHeap, | |
171 | kAddressKindStack, | |
172 | kAddressKindGlobal, | |
173 | }; | |
174 | ||
175 | class AddressDescription { | |
176 | struct AddressDescriptionData { | |
177 | AddressKind kind; | |
178 | union { | |
179 | ShadowAddressDescription shadow; | |
180 | HeapAddressDescription heap; | |
181 | StackAddressDescription stack; | |
182 | GlobalAddressDescription global; | |
183 | uptr addr; | |
184 | }; | |
185 | }; | |
186 | ||
187 | AddressDescriptionData data; | |
188 | ||
189 | public: | |
190 | AddressDescription() = default; | |
191 | // shouldLockThreadRegistry allows us to skip locking if we're sure we already | |
192 | // have done it. | |
193 | AddressDescription(uptr addr, bool shouldLockThreadRegistry = true) | |
194 | : AddressDescription(addr, 1, shouldLockThreadRegistry) {} | |
195 | AddressDescription(uptr addr, uptr access_size, | |
196 | bool shouldLockThreadRegistry = true); | |
197 | ||
198 | uptr Address() const { | |
199 | switch (data.kind) { | |
200 | case kAddressKindWild: | |
201 | return data.addr; | |
202 | case kAddressKindShadow: | |
203 | return data.shadow.addr; | |
204 | case kAddressKindHeap: | |
205 | return data.heap.addr; | |
206 | case kAddressKindStack: | |
207 | return data.stack.addr; | |
208 | case kAddressKindGlobal: | |
209 | return data.global.addr; | |
210 | } | |
211 | UNREACHABLE("AddressInformation kind is invalid"); | |
212 | } | |
213 | void Print(const char *bug_descr = nullptr) const { | |
214 | switch (data.kind) { | |
215 | case kAddressKindWild: | |
216 | Printf("Address %p is a wild pointer.\n", data.addr); | |
217 | return; | |
218 | case kAddressKindShadow: | |
219 | return data.shadow.Print(); | |
220 | case kAddressKindHeap: | |
221 | return data.heap.Print(); | |
222 | case kAddressKindStack: | |
223 | return data.stack.Print(); | |
224 | case kAddressKindGlobal: | |
225 | // initialization-order-fiasco has a special Print() | |
226 | return data.global.Print(bug_descr); | |
227 | } | |
228 | UNREACHABLE("AddressInformation kind is invalid"); | |
229 | } | |
230 | ||
231 | void StoreTo(AddressDescriptionData *dst) const { *dst = data; } | |
232 | ||
233 | const ShadowAddressDescription *AsShadow() const { | |
234 | return data.kind == kAddressKindShadow ? &data.shadow : nullptr; | |
235 | } | |
236 | const HeapAddressDescription *AsHeap() const { | |
237 | return data.kind == kAddressKindHeap ? &data.heap : nullptr; | |
238 | } | |
239 | const StackAddressDescription *AsStack() const { | |
240 | return data.kind == kAddressKindStack ? &data.stack : nullptr; | |
241 | } | |
242 | const GlobalAddressDescription *AsGlobal() const { | |
243 | return data.kind == kAddressKindGlobal ? &data.global : nullptr; | |
244 | } | |
245 | }; | |
246 | ||
247 | } // namespace __asan | |
248 | ||
249 | #endif // ASAN_DESCRIPTIONS_H |