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 
22 namespace __asan {
23 
24 void DescribeThread(AsanThreadContext *context);
DescribeThread(AsanThread * t)25 static inline void DescribeThread(AsanThread *t) {
26   if (t) DescribeThread(t->context());
27 }
28 
29 class 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.
c_str()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 
43 class Decorator : public __sanitizer::SanitizerCommonDecorator {
44  public:
Decorator()45   Decorator() : SanitizerCommonDecorator() {}
Access()46   const char *Access() { return Blue(); }
Location()47   const char *Location() { return Green(); }
Allocation()48   const char *Allocation() { return Magenta(); }
49 
ShadowByte(u8 byte)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 
84 enum ShadowKind : u8 {
85   kShadowKindLow,
86   kShadowKindGap,
87   kShadowKindHigh,
88 };
89 static const char *const ShadowNames[] = {"low shadow", "shadow gap",
90                                           "high shadow"};
91 
92 struct ShadowAddressDescription {
93   uptr addr;
94   ShadowKind kind;
95   u8 shadow_byte;
96 
97   void Print() const;
98 };
99 
100 bool GetShadowAddressInformation(uptr addr, ShadowAddressDescription *descr);
101 bool DescribeAddressIfShadow(uptr addr);
102 
103 enum AccessType {
104   kAccessTypeLeft,
105   kAccessTypeRight,
106   kAccessTypeInside,
107   kAccessTypeUnknown,  // This means we have an AddressSanitizer bug!
108 };
109 
110 struct 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 
120 struct 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 
131 bool GetHeapAddressInformation(uptr addr, uptr access_size,
132                                HeapAddressDescription *descr);
133 bool DescribeAddressIfHeap(uptr addr, uptr access_size = 1);
134 
135 struct 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 
146 bool GetStackAddressInformation(uptr addr, uptr access_size,
147                                 StackAddressDescription *descr);
148 
149 struct GlobalAddressDescription {
150   uptr addr;
151   // Assume address is close to at most four globals.
152   static const int kMaxGlobals = 4;
153   __asan_global globals[kMaxGlobals];
154   u32 reg_sites[kMaxGlobals];
155   uptr access_size;
156   u8 size;
157 
158   void Print(const char *bug_type = "") const;
159 
160   // Returns true when this descriptions points inside the same global variable
161   // as other. Descriptions can have different address within the variable
162   bool PointsInsideTheSameVariable(const GlobalAddressDescription &other) const;
163 };
164 
165 bool GetGlobalAddressInformation(uptr addr, uptr access_size,
166                                  GlobalAddressDescription *descr);
167 bool DescribeAddressIfGlobal(uptr addr, uptr access_size, const char *bug_type);
168 
169 // General function to describe an address. Will try to describe the address as
170 // a shadow, global (variable), stack, or heap address.
171 // bug_type is optional and is used for checking if we're reporting an
172 // initialization-order-fiasco
173 // The proper access_size should be passed for stack, global, and heap
174 // addresses. Defaults to 1.
175 // Each of the *AddressDescription functions has its own Print() member, which
176 // may take access_size and bug_type parameters if needed.
177 void PrintAddressDescription(uptr addr, uptr access_size = 1,
178                              const char *bug_type = "");
179 
180 enum AddressKind {
181   kAddressKindWild,
182   kAddressKindShadow,
183   kAddressKindHeap,
184   kAddressKindStack,
185   kAddressKindGlobal,
186 };
187 
188 class AddressDescription {
189   struct AddressDescriptionData {
190     AddressKind kind;
191     union {
192       ShadowAddressDescription shadow;
193       HeapAddressDescription heap;
194       StackAddressDescription stack;
195       GlobalAddressDescription global;
196       uptr addr;
197     };
198   };
199 
200   AddressDescriptionData data;
201 
202  public:
203   AddressDescription() = default;
204   // shouldLockThreadRegistry allows us to skip locking if we're sure we already
205   // have done it.
206   explicit AddressDescription(uptr addr, bool shouldLockThreadRegistry = true)
207       : AddressDescription(addr, 1, shouldLockThreadRegistry) {}
208   AddressDescription(uptr addr, uptr access_size,
209                      bool shouldLockThreadRegistry = true);
210 
Address()211   uptr Address() const {
212     switch (data.kind) {
213       case kAddressKindWild:
214         return data.addr;
215       case kAddressKindShadow:
216         return data.shadow.addr;
217       case kAddressKindHeap:
218         return data.heap.addr;
219       case kAddressKindStack:
220         return data.stack.addr;
221       case kAddressKindGlobal:
222         return data.global.addr;
223     }
224     UNREACHABLE("AddressInformation kind is invalid");
225   }
226   void Print(const char *bug_descr = nullptr) const {
227     switch (data.kind) {
228       case kAddressKindWild:
229         Printf("Address %p is a wild pointer.\n", data.addr);
230         return;
231       case kAddressKindShadow:
232         return data.shadow.Print();
233       case kAddressKindHeap:
234         return data.heap.Print();
235       case kAddressKindStack:
236         return data.stack.Print();
237       case kAddressKindGlobal:
238         // initialization-order-fiasco has a special Print()
239         return data.global.Print(bug_descr);
240     }
241     UNREACHABLE("AddressInformation kind is invalid");
242   }
243 
StoreTo(AddressDescriptionData * dst)244   void StoreTo(AddressDescriptionData *dst) const { *dst = data; }
245 
AsShadow()246   const ShadowAddressDescription *AsShadow() const {
247     return data.kind == kAddressKindShadow ? &data.shadow : nullptr;
248   }
AsHeap()249   const HeapAddressDescription *AsHeap() const {
250     return data.kind == kAddressKindHeap ? &data.heap : nullptr;
251   }
AsStack()252   const StackAddressDescription *AsStack() const {
253     return data.kind == kAddressKindStack ? &data.stack : nullptr;
254   }
AsGlobal()255   const GlobalAddressDescription *AsGlobal() const {
256     return data.kind == kAddressKindGlobal ? &data.global : nullptr;
257   }
258 };
259 
260 }  // namespace __asan
261 
262 #endif  // ASAN_DESCRIPTIONS_H
263