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