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