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 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(); } 48 const char *Allocation() { return Magenta(); } 49 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 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 244 void StoreTo(AddressDescriptionData *dst) const { *dst = data; } 245 246 const ShadowAddressDescription *AsShadow() const { 247 return data.kind == kAddressKindShadow ? &data.shadow : nullptr; 248 } 249 const HeapAddressDescription *AsHeap() const { 250 return data.kind == kAddressKindHeap ? &data.heap : nullptr; 251 } 252 const StackAddressDescription *AsStack() const { 253 return data.kind == kAddressKindStack ? &data.stack : nullptr; 254 } 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