1 //===-- asan_descriptions.cc ------------------------------------*- C++ -*-===// 2 // 3 // This file is distributed under the University of Illinois Open Source 4 // License. See LICENSE.TXT for details. 5 // 6 //===----------------------------------------------------------------------===// 7 // 8 // This file is a part of AddressSanitizer, an address sanity checker. 9 // 10 // ASan functions for getting information about an address and/or printing it. 11 //===----------------------------------------------------------------------===// 12 13 #include "asan_descriptions.h" 14 #include "asan_mapping.h" 15 #include "asan_report.h" 16 #include "asan_stack.h" 17 #include "sanitizer_common/sanitizer_stackdepot.h" 18 19 namespace __asan { 20 21 // Return " (thread_name) " or an empty string if the name is empty. 22 const char *ThreadNameWithParenthesis(AsanThreadContext *t, char buff[], 23 uptr buff_len) { 24 const char *name = t->name; 25 if (name[0] == '\0') return ""; 26 buff[0] = 0; 27 internal_strncat(buff, " (", 3); 28 internal_strncat(buff, name, buff_len - 4); 29 internal_strncat(buff, ")", 2); 30 return buff; 31 } 32 33 const char *ThreadNameWithParenthesis(u32 tid, char buff[], uptr buff_len) { 34 if (tid == kInvalidTid) return ""; 35 asanThreadRegistry().CheckLocked(); 36 AsanThreadContext *t = GetThreadContextByTidLocked(tid); 37 return ThreadNameWithParenthesis(t, buff, buff_len); 38 } 39 40 void DescribeThread(AsanThreadContext *context) { 41 CHECK(context); 42 asanThreadRegistry().CheckLocked(); 43 // No need to announce the main thread. 44 if (context->tid == 0 || context->announced) { 45 return; 46 } 47 context->announced = true; 48 char tname[128]; 49 InternalScopedString str(1024); 50 str.append("Thread T%d%s", context->tid, 51 ThreadNameWithParenthesis(context->tid, tname, sizeof(tname))); 52 if (context->parent_tid == kInvalidTid) { 53 str.append(" created by unknown thread\n"); 54 Printf("%s", str.data()); 55 return; 56 } 57 str.append( 58 " created by T%d%s here:\n", context->parent_tid, 59 ThreadNameWithParenthesis(context->parent_tid, tname, sizeof(tname))); 60 Printf("%s", str.data()); 61 StackDepotGet(context->stack_id).Print(); 62 // Recursively described parent thread if needed. 63 if (flags()->print_full_thread_history) { 64 AsanThreadContext *parent_context = 65 GetThreadContextByTidLocked(context->parent_tid); 66 DescribeThread(parent_context); 67 } 68 } 69 70 // Shadow descriptions 71 static bool GetShadowKind(uptr addr, ShadowKind *shadow_kind) { 72 CHECK(!AddrIsInMem(addr)); 73 if (AddrIsInShadowGap(addr)) { 74 *shadow_kind = kShadowKindGap; 75 } else if (AddrIsInHighShadow(addr)) { 76 *shadow_kind = kShadowKindHigh; 77 } else if (AddrIsInLowShadow(addr)) { 78 *shadow_kind = kShadowKindLow; 79 } else { 80 CHECK(0 && "Address is not in memory and not in shadow?"); 81 return false; 82 } 83 return true; 84 } 85 86 bool DescribeAddressIfShadow(uptr addr) { 87 ShadowAddressDescription descr; 88 if (!GetShadowAddressInformation(addr, &descr)) return false; 89 descr.Print(); 90 return true; 91 } 92 93 bool GetShadowAddressInformation(uptr addr, ShadowAddressDescription *descr) { 94 if (AddrIsInMem(addr)) return false; 95 ShadowKind shadow_kind; 96 if (!GetShadowKind(addr, &shadow_kind)) return false; 97 if (shadow_kind != kShadowKindGap) descr->shadow_byte = *(u8 *)addr; 98 descr->addr = addr; 99 descr->kind = shadow_kind; 100 return true; 101 } 102 103 // Heap descriptions 104 static void GetAccessToHeapChunkInformation(ChunkAccess *descr, 105 AsanChunkView chunk, uptr addr, 106 uptr access_size) { 107 descr->bad_addr = addr; 108 if (chunk.AddrIsAtLeft(addr, access_size, &descr->offset)) { 109 descr->access_type = kAccessTypeLeft; 110 } else if (chunk.AddrIsAtRight(addr, access_size, &descr->offset)) { 111 descr->access_type = kAccessTypeRight; 112 if (descr->offset < 0) { 113 descr->bad_addr -= descr->offset; 114 descr->offset = 0; 115 } 116 } else if (chunk.AddrIsInside(addr, access_size, &descr->offset)) { 117 descr->access_type = kAccessTypeInside; 118 } else { 119 descr->access_type = kAccessTypeUnknown; 120 } 121 descr->chunk_begin = chunk.Beg(); 122 descr->chunk_size = chunk.UsedSize(); 123 descr->alloc_type = chunk.GetAllocType(); 124 } 125 126 static void PrintHeapChunkAccess(uptr addr, const ChunkAccess &descr) { 127 Decorator d; 128 InternalScopedString str(4096); 129 str.append("%s", d.Location()); 130 switch (descr.access_type) { 131 case kAccessTypeLeft: 132 str.append("%p is located %zd bytes to the left of", 133 (void *)descr.bad_addr, descr.offset); 134 break; 135 case kAccessTypeRight: 136 str.append("%p is located %zd bytes to the right of", 137 (void *)descr.bad_addr, descr.offset); 138 break; 139 case kAccessTypeInside: 140 str.append("%p is located %zd bytes inside of", (void *)descr.bad_addr, 141 descr.offset); 142 break; 143 case kAccessTypeUnknown: 144 str.append( 145 "%p is located somewhere around (this is AddressSanitizer bug!)", 146 (void *)descr.bad_addr); 147 } 148 str.append(" %zu-byte region [%p,%p)\n", descr.chunk_size, 149 (void *)descr.chunk_begin, 150 (void *)(descr.chunk_begin + descr.chunk_size)); 151 str.append("%s", d.EndLocation()); 152 Printf("%s", str.data()); 153 } 154 155 bool GetHeapAddressInformation(uptr addr, uptr access_size, 156 HeapAddressDescription *descr) { 157 AsanChunkView chunk = FindHeapChunkByAddress(addr); 158 if (!chunk.IsValid()) { 159 return false; 160 } 161 descr->addr = addr; 162 GetAccessToHeapChunkInformation(&descr->chunk_access, chunk, addr, 163 access_size); 164 CHECK_NE(chunk.AllocTid(), kInvalidTid); 165 descr->alloc_tid = chunk.AllocTid(); 166 descr->alloc_stack_id = chunk.GetAllocStackId(); 167 descr->free_tid = chunk.FreeTid(); 168 if (descr->free_tid != kInvalidTid) 169 descr->free_stack_id = chunk.GetFreeStackId(); 170 return true; 171 } 172 173 static StackTrace GetStackTraceFromId(u32 id) { 174 CHECK(id); 175 StackTrace res = StackDepotGet(id); 176 CHECK(res.trace); 177 return res; 178 } 179 180 bool DescribeAddressIfHeap(uptr addr, uptr access_size) { 181 HeapAddressDescription descr; 182 if (!GetHeapAddressInformation(addr, access_size, &descr)) { 183 Printf( 184 "AddressSanitizer can not describe address in more detail " 185 "(wild memory access suspected).\n"); 186 return false; 187 } 188 descr.Print(); 189 return true; 190 } 191 192 // Stack descriptions 193 bool GetStackAddressInformation(uptr addr, uptr access_size, 194 StackAddressDescription *descr) { 195 AsanThread *t = FindThreadByStackAddress(addr); 196 if (!t) return false; 197 198 descr->addr = addr; 199 descr->tid = t->tid(); 200 // Try to fetch precise stack frame for this access. 201 AsanThread::StackFrameAccess access; 202 if (!t->GetStackFrameAccessByAddr(addr, &access)) { 203 descr->frame_descr = nullptr; 204 return true; 205 } 206 207 descr->offset = access.offset; 208 descr->access_size = access_size; 209 descr->frame_pc = access.frame_pc; 210 descr->frame_descr = access.frame_descr; 211 212 #if SANITIZER_PPC64V1 213 // On PowerPC64 ELFv1, the address of a function actually points to a 214 // three-doubleword data structure with the first field containing 215 // the address of the function's code. 216 descr->frame_pc = *reinterpret_cast<uptr *>(descr->frame_pc); 217 #endif 218 descr->frame_pc += 16; 219 220 return true; 221 } 222 223 static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr, 224 uptr access_size, uptr prev_var_end, 225 uptr next_var_beg) { 226 uptr var_end = var.beg + var.size; 227 uptr addr_end = addr + access_size; 228 const char *pos_descr = nullptr; 229 // If the variable [var.beg, var_end) is the nearest variable to the 230 // current memory access, indicate it in the log. 231 if (addr >= var.beg) { 232 if (addr_end <= var_end) 233 pos_descr = "is inside"; // May happen if this is a use-after-return. 234 else if (addr < var_end) 235 pos_descr = "partially overflows"; 236 else if (addr_end <= next_var_beg && 237 next_var_beg - addr_end >= addr - var_end) 238 pos_descr = "overflows"; 239 } else { 240 if (addr_end > var.beg) 241 pos_descr = "partially underflows"; 242 else if (addr >= prev_var_end && addr - prev_var_end >= var.beg - addr_end) 243 pos_descr = "underflows"; 244 } 245 InternalScopedString str(1024); 246 str.append(" [%zd, %zd)", var.beg, var_end); 247 // Render variable name. 248 str.append(" '"); 249 for (uptr i = 0; i < var.name_len; ++i) { 250 str.append("%c", var.name_pos[i]); 251 } 252 str.append("'"); 253 if (pos_descr) { 254 Decorator d; 255 // FIXME: we may want to also print the size of the access here, 256 // but in case of accesses generated by memset it may be confusing. 257 str.append("%s <== Memory access at offset %zd %s this variable%s\n", 258 d.Location(), addr, pos_descr, d.EndLocation()); 259 } else { 260 str.append("\n"); 261 } 262 Printf("%s", str.data()); 263 } 264 265 bool DescribeAddressIfStack(uptr addr, uptr access_size) { 266 StackAddressDescription descr; 267 if (!GetStackAddressInformation(addr, access_size, &descr)) return false; 268 descr.Print(); 269 return true; 270 } 271 272 // Global descriptions 273 static void DescribeAddressRelativeToGlobal(uptr addr, uptr access_size, 274 const __asan_global &g) { 275 InternalScopedString str(4096); 276 Decorator d; 277 str.append("%s", d.Location()); 278 if (addr < g.beg) { 279 str.append("%p is located %zd bytes to the left", (void *)addr, 280 g.beg - addr); 281 } else if (addr + access_size > g.beg + g.size) { 282 if (addr < g.beg + g.size) addr = g.beg + g.size; 283 str.append("%p is located %zd bytes to the right", (void *)addr, 284 addr - (g.beg + g.size)); 285 } else { 286 // Can it happen? 287 str.append("%p is located %zd bytes inside", (void *)addr, addr - g.beg); 288 } 289 str.append(" of global variable '%s' defined in '", 290 MaybeDemangleGlobalName(g.name)); 291 PrintGlobalLocation(&str, g); 292 str.append("' (0x%zx) of size %zu\n", g.beg, g.size); 293 str.append("%s", d.EndLocation()); 294 PrintGlobalNameIfASCII(&str, g); 295 Printf("%s", str.data()); 296 } 297 298 bool GetGlobalAddressInformation(uptr addr, uptr access_size, 299 GlobalAddressDescription *descr) { 300 descr->addr = addr; 301 int globals_num = GetGlobalsForAddress(addr, descr->globals, descr->reg_sites, 302 ARRAY_SIZE(descr->globals)); 303 descr->size = globals_num; 304 descr->access_size = access_size; 305 return globals_num != 0; 306 } 307 308 bool DescribeAddressIfGlobal(uptr addr, uptr access_size, 309 const char *bug_type) { 310 GlobalAddressDescription descr; 311 if (!GetGlobalAddressInformation(addr, access_size, &descr)) return false; 312 313 descr.Print(bug_type); 314 return true; 315 } 316 317 void ShadowAddressDescription::Print() const { 318 Printf("Address %p is located in the %s area.\n", addr, ShadowNames[kind]); 319 } 320 321 void GlobalAddressDescription::Print(const char *bug_type) const { 322 for (int i = 0; i < size; i++) { 323 DescribeAddressRelativeToGlobal(addr, access_size, globals[i]); 324 if (bug_type && 325 0 == internal_strcmp(bug_type, "initialization-order-fiasco") && 326 reg_sites[i]) { 327 Printf(" registered at:\n"); 328 StackDepotGet(reg_sites[i]).Print(); 329 } 330 } 331 } 332 333 void StackAddressDescription::Print() const { 334 Decorator d; 335 char tname[128]; 336 Printf("%s", d.Location()); 337 Printf("Address %p is located in stack of thread T%d%s", addr, tid, 338 ThreadNameWithParenthesis(tid, tname, sizeof(tname))); 339 340 if (!frame_descr) { 341 Printf("%s\n", d.EndLocation()); 342 return; 343 } 344 Printf(" at offset %zu in frame%s\n", offset, d.EndLocation()); 345 346 // Now we print the frame where the alloca has happened. 347 // We print this frame as a stack trace with one element. 348 // The symbolizer may print more than one frame if inlining was involved. 349 // The frame numbers may be different than those in the stack trace printed 350 // previously. That's unfortunate, but I have no better solution, 351 // especially given that the alloca may be from entirely different place 352 // (e.g. use-after-scope, or different thread's stack). 353 Printf("%s", d.EndLocation()); 354 StackTrace alloca_stack(&frame_pc, 1); 355 alloca_stack.Print(); 356 357 InternalMmapVector<StackVarDescr> vars(16); 358 if (!ParseFrameDescription(frame_descr, &vars)) { 359 Printf( 360 "AddressSanitizer can't parse the stack frame " 361 "descriptor: |%s|\n", 362 frame_descr); 363 // 'addr' is a stack address, so return true even if we can't parse frame 364 return; 365 } 366 uptr n_objects = vars.size(); 367 // Report the number of stack objects. 368 Printf(" This frame has %zu object(s):\n", n_objects); 369 370 // Report all objects in this frame. 371 for (uptr i = 0; i < n_objects; i++) { 372 uptr prev_var_end = i ? vars[i - 1].beg + vars[i - 1].size : 0; 373 uptr next_var_beg = i + 1 < n_objects ? vars[i + 1].beg : ~(0UL); 374 PrintAccessAndVarIntersection(vars[i], offset, access_size, prev_var_end, 375 next_var_beg); 376 } 377 Printf( 378 "HINT: this may be a false positive if your program uses " 379 "some custom stack unwind mechanism or swapcontext\n"); 380 if (SANITIZER_WINDOWS) 381 Printf(" (longjmp, SEH and C++ exceptions *are* supported)\n"); 382 else 383 Printf(" (longjmp and C++ exceptions *are* supported)\n"); 384 385 DescribeThread(GetThreadContextByTidLocked(tid)); 386 } 387 388 void HeapAddressDescription::Print() const { 389 PrintHeapChunkAccess(addr, chunk_access); 390 391 asanThreadRegistry().CheckLocked(); 392 AsanThreadContext *alloc_thread = GetThreadContextByTidLocked(alloc_tid); 393 StackTrace alloc_stack = GetStackTraceFromId(alloc_stack_id); 394 395 char tname[128]; 396 Decorator d; 397 AsanThreadContext *free_thread = nullptr; 398 if (free_tid != kInvalidTid) { 399 free_thread = GetThreadContextByTidLocked(free_tid); 400 Printf("%sfreed by thread T%d%s here:%s\n", d.Allocation(), 401 free_thread->tid, 402 ThreadNameWithParenthesis(free_thread, tname, sizeof(tname)), 403 d.EndAllocation()); 404 StackTrace free_stack = GetStackTraceFromId(free_stack_id); 405 free_stack.Print(); 406 Printf("%spreviously allocated by thread T%d%s here:%s\n", d.Allocation(), 407 alloc_thread->tid, 408 ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)), 409 d.EndAllocation()); 410 } else { 411 Printf("%sallocated by thread T%d%s here:%s\n", d.Allocation(), 412 alloc_thread->tid, 413 ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)), 414 d.EndAllocation()); 415 } 416 alloc_stack.Print(); 417 DescribeThread(GetCurrentThread()); 418 if (free_thread) DescribeThread(free_thread); 419 DescribeThread(alloc_thread); 420 } 421 422 AddressDescription::AddressDescription(uptr addr, uptr access_size, 423 bool shouldLockThreadRegistry) { 424 if (GetShadowAddressInformation(addr, &data.shadow)) { 425 data.kind = kAddressKindShadow; 426 return; 427 } 428 if (GetHeapAddressInformation(addr, access_size, &data.heap)) { 429 data.kind = kAddressKindHeap; 430 return; 431 } 432 433 bool isStackMemory = false; 434 if (shouldLockThreadRegistry) { 435 ThreadRegistryLock l(&asanThreadRegistry()); 436 isStackMemory = GetStackAddressInformation(addr, access_size, &data.stack); 437 } else { 438 isStackMemory = GetStackAddressInformation(addr, access_size, &data.stack); 439 } 440 if (isStackMemory) { 441 data.kind = kAddressKindStack; 442 return; 443 } 444 445 if (GetGlobalAddressInformation(addr, access_size, &data.global)) { 446 data.kind = kAddressKindGlobal; 447 return; 448 } 449 data.kind = kAddressKindWild; 450 addr = 0; 451 } 452 453 void PrintAddressDescription(uptr addr, uptr access_size, 454 const char *bug_type) { 455 ShadowAddressDescription shadow_descr; 456 if (GetShadowAddressInformation(addr, &shadow_descr)) { 457 shadow_descr.Print(); 458 return; 459 } 460 461 GlobalAddressDescription global_descr; 462 if (GetGlobalAddressInformation(addr, access_size, &global_descr)) { 463 global_descr.Print(bug_type); 464 return; 465 } 466 467 StackAddressDescription stack_descr; 468 if (GetStackAddressInformation(addr, access_size, &stack_descr)) { 469 stack_descr.Print(); 470 return; 471 } 472 473 HeapAddressDescription heap_descr; 474 if (GetHeapAddressInformation(addr, access_size, &heap_descr)) { 475 heap_descr.Print(); 476 return; 477 } 478 479 // We exhausted our possibilities. Bail out. 480 Printf( 481 "AddressSanitizer can not describe address in more detail " 482 "(wild memory access suspected).\n"); 483 } 484 } // namespace __asan 485