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);
DescribeThread(AsanThread * t)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:
Decorator()33 Decorator() : SanitizerCommonDecorator() {}
Access()34 const char *Access() { return Blue(); }
Location()35 const char *Location() { return Green(); }
Allocation()36 const char *Allocation() { return Magenta(); }
37
ShadowByte(u8 byte)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 }
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;
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;
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
Address()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
StoreTo(AddressDescriptionData * dst)231 void StoreTo(AddressDescriptionData *dst) const { *dst = data; }
232
AsShadow()233 const ShadowAddressDescription *AsShadow() const {
234 return data.kind == kAddressKindShadow ? &data.shadow : nullptr;
235 }
AsHeap()236 const HeapAddressDescription *AsHeap() const {
237 return data.kind == kAddressKindHeap ? &data.heap : nullptr;
238 }
AsStack()239 const StackAddressDescription *AsStack() const {
240 return data.kind == kAddressKindStack ? &data.stack : nullptr;
241 }
AsGlobal()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
250