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