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