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