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);
getComment(const NamedDecl * D) const25 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.
ClangDocSerializeTestVisitor(EmittedInfoList & EmittedInfos,bool Public)35   const char *c_str() const { return &name[0]; }
36 
37  private:
mapDecl(const T * D)38   void Init(u32 tid, const char *tname);
39 
40   char name[128];
41 };
42 
43 class Decorator : public __sanitizer::SanitizerCommonDecorator {
44  public:
45   Decorator() : SanitizerCommonDecorator() {}
46   const char *Access() { return Blue(); }
47   const char *Location() { return Green(); }
VisitNamespaceDecl(const NamespaceDecl * D)48   const char *Allocation() { return Magenta(); }
49 
VisitFunctionDecl(const FunctionDecl * D)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 
TEST(SerializeTest,emitNamespaceInfo)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 {
TEST(SerializeTest,emitAnonymousNamespaceInfo)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;
TEST(SerializeTest,emitRecordInfo)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 WildAddressDescription {
150   uptr addr;
151   uptr access_size;
152 
153   void Print() const;
154 };
155 
156 struct GlobalAddressDescription {
157   uptr addr;
158   // Assume address is close to at most four globals.
159   static const int kMaxGlobals = 4;
160   __asan_global globals[kMaxGlobals];
161   u32 reg_sites[kMaxGlobals];
162   uptr access_size;
163   u8 size;
164 
165   void Print(const char *bug_type = "") const;
166 
167   // Returns true when this descriptions points inside the same global variable
168   // as other. Descriptions can have different address within the variable
169   bool PointsInsideTheSameVariable(const GlobalAddressDescription &other) const;
170 };
171 
172 bool GetGlobalAddressInformation(uptr addr, uptr access_size,
173                                  GlobalAddressDescription *descr);
174 bool DescribeAddressIfGlobal(uptr addr, uptr access_size, const char *bug_type);
175 
176 // General function to describe an address. Will try to describe the address as
177 // a shadow, global (variable), stack, or heap address.
178 // bug_type is optional and is used for checking if we're reporting an
179 // initialization-order-fiasco
180 // The proper access_size should be passed for stack, global, and heap
181 // addresses. Defaults to 1.
182 // Each of the *AddressDescription functions has its own Print() member, which
183 // may take access_size and bug_type parameters if needed.
184 void PrintAddressDescription(uptr addr, uptr access_size = 1,
185                              const char *bug_type = "");
186 
187 enum AddressKind {
188   kAddressKindWild,
189   kAddressKindShadow,
190   kAddressKindHeap,
191   kAddressKindStack,
192   kAddressKindGlobal,
193 };
194 
195 class AddressDescription {
196   struct AddressDescriptionData {
197     AddressKind kind;
198     union {
199       ShadowAddressDescription shadow;
200       HeapAddressDescription heap;
201       StackAddressDescription stack;
202       GlobalAddressDescription global;
203       WildAddressDescription wild;
204     };
205   };
206 
207   AddressDescriptionData data;
208 
209  public:
210   AddressDescription() = default;
211   // shouldLockThreadRegistry allows us to skip locking if we're sure we already
212   // have done it.
213   explicit AddressDescription(uptr addr, bool shouldLockThreadRegistry = true)
214       : AddressDescription(addr, 1, shouldLockThreadRegistry) {}
215   AddressDescription(uptr addr, uptr access_size,
216                      bool shouldLockThreadRegistry = true);
217 
218   uptr Address() const {
219     switch (data.kind) {
220       case kAddressKindWild:
221         return data.wild.addr;
222       case kAddressKindShadow:
223         return data.shadow.addr;
224       case kAddressKindHeap:
225         return data.heap.addr;
226       case kAddressKindStack:
227         return data.stack.addr;
228       case kAddressKindGlobal:
229         return data.global.addr;
230     }
231     UNREACHABLE("AddressInformation kind is invalid");
232   }
TEST(SerializeTest,emitEnumInfo)233   void Print(const char *bug_descr = nullptr) const {
234     switch (data.kind) {
235       case kAddressKindWild:
236         data.wild.Print();
237         return;
238       case kAddressKindShadow:
239         return data.shadow.Print();
240       case kAddressKindHeap:
241         return data.heap.Print();
242       case kAddressKindStack:
243         return data.stack.Print();
244       case kAddressKindGlobal:
245         // initialization-order-fiasco has a special Print()
246         return data.global.Print(bug_descr);
247     }
248     UNREACHABLE("AddressInformation kind is invalid");
249   }
250 
251   void StoreTo(AddressDescriptionData *dst) const { *dst = data; }
252 
253   const ShadowAddressDescription *AsShadow() const {
254     return data.kind == kAddressKindShadow ? &data.shadow : nullptr;
255   }
256   const HeapAddressDescription *AsHeap() const {
257     return data.kind == kAddressKindHeap ? &data.heap : nullptr;
258   }
259   const StackAddressDescription *AsStack() const {
TEST(SerializeTest,emitUndefinedRecordInfo)260     return data.kind == kAddressKindStack ? &data.stack : nullptr;
261   }
262   const GlobalAddressDescription *AsGlobal() const {
263     return data.kind == kAddressKindGlobal ? &data.global : nullptr;
264   }
265 };
266 
267 }  // namespace __asan
268 
269 #endif  // ASAN_DESCRIPTIONS_H
270