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