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