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
22namespace __asan {
23
24void DescribeThread(AsanThreadContext *context);
25static inline void DescribeThread(AsanThread *t) {
26 if (t) DescribeThread(context: t->context());
27}
28
29class 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
43class 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
84enum ShadowKind : u8 {
85 kShadowKindLow,
86 kShadowKindGap,
87 kShadowKindHigh,
88};
89static const char *const ShadowNames[] = {"low shadow", "shadow gap",
90 "high shadow"};
91
92struct ShadowAddressDescription {
93 uptr addr;
94 ShadowKind kind;
95 u8 shadow_byte;
96
97 void Print() const;
98};
99
100bool GetShadowAddressInformation(uptr addr, ShadowAddressDescription *descr);
101bool DescribeAddressIfShadow(uptr addr);
102
103enum AccessType {
104 kAccessTypeLeft,
105 kAccessTypeRight,
106 kAccessTypeInside,
107 kAccessTypeUnknown, // This means we have an AddressSanitizer bug!
108};
109
110struct 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
120struct 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
131bool GetHeapAddressInformation(uptr addr, uptr access_size,
132 HeapAddressDescription *descr);
133bool DescribeAddressIfHeap(uptr addr, uptr access_size = 1);
134
135struct 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
146bool GetStackAddressInformation(uptr addr, uptr access_size,
147 StackAddressDescription *descr);
148
149struct WildAddressDescription {
150 uptr addr;
151 uptr access_size;
152
153 void Print() const;
154};
155
156struct 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
172bool GetGlobalAddressInformation(uptr addr, uptr access_size,
173 GlobalAddressDescription *descr);
174bool 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.
184void PrintAddressDescription(uptr addr, uptr access_size = 1,
185 const char *bug_type = "");
186
187enum AddressKind {
188 kAddressKindWild,
189 kAddressKindShadow,
190 kAddressKindHeap,
191 kAddressKindStack,
192 kAddressKindGlobal,
193};
194
195class 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