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