168d75effSDimitry Andric //===-- asan_descriptions.cpp -----------------------------------*- C++ -*-===// 268d75effSDimitry Andric // 368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 668d75effSDimitry Andric // 768d75effSDimitry Andric //===----------------------------------------------------------------------===// 868d75effSDimitry Andric // 968d75effSDimitry Andric // This file is a part of AddressSanitizer, an address sanity checker. 1068d75effSDimitry Andric // 1168d75effSDimitry Andric // ASan functions for getting information about an address and/or printing it. 1268d75effSDimitry Andric //===----------------------------------------------------------------------===// 1368d75effSDimitry Andric 1468d75effSDimitry Andric #include "asan_descriptions.h" 1568d75effSDimitry Andric #include "asan_mapping.h" 1668d75effSDimitry Andric #include "asan_report.h" 1768d75effSDimitry Andric #include "asan_stack.h" 1868d75effSDimitry Andric #include "sanitizer_common/sanitizer_stackdepot.h" 1968d75effSDimitry Andric 2068d75effSDimitry Andric namespace __asan { 2168d75effSDimitry Andric 2268d75effSDimitry Andric AsanThreadIdAndName::AsanThreadIdAndName(AsanThreadContext *t) { 2368d75effSDimitry Andric Init(t->tid, t->name); 2468d75effSDimitry Andric } 2568d75effSDimitry Andric 2668d75effSDimitry Andric AsanThreadIdAndName::AsanThreadIdAndName(u32 tid) { 2768d75effSDimitry Andric if (tid == kInvalidTid) { 2868d75effSDimitry Andric Init(tid, ""); 2968d75effSDimitry Andric } else { 3068d75effSDimitry Andric asanThreadRegistry().CheckLocked(); 3168d75effSDimitry Andric AsanThreadContext *t = GetThreadContextByTidLocked(tid); 3268d75effSDimitry Andric Init(tid, t->name); 3368d75effSDimitry Andric } 3468d75effSDimitry Andric } 3568d75effSDimitry Andric 3668d75effSDimitry Andric void AsanThreadIdAndName::Init(u32 tid, const char *tname) { 3768d75effSDimitry Andric int len = internal_snprintf(name, sizeof(name), "T%d", tid); 3868d75effSDimitry Andric CHECK(((unsigned int)len) < sizeof(name)); 3968d75effSDimitry Andric if (tname[0] != '\0') 4068d75effSDimitry Andric internal_snprintf(&name[len], sizeof(name) - len, " (%s)", tname); 4168d75effSDimitry Andric } 4268d75effSDimitry Andric 4368d75effSDimitry Andric void DescribeThread(AsanThreadContext *context) { 4468d75effSDimitry Andric CHECK(context); 4568d75effSDimitry Andric asanThreadRegistry().CheckLocked(); 4668d75effSDimitry Andric // No need to announce the main thread. 47fe6060f1SDimitry Andric if (context->tid == kMainTid || context->announced) { 4868d75effSDimitry Andric return; 4968d75effSDimitry Andric } 5068d75effSDimitry Andric context->announced = true; 51fe6060f1SDimitry Andric InternalScopedString str; 525f757f3fSDimitry Andric str.AppendF("Thread %s", AsanThreadIdAndName(context).c_str()); 5368d75effSDimitry Andric if (context->parent_tid == kInvalidTid) { 545f757f3fSDimitry Andric str.Append(" created by unknown thread\n"); 5568d75effSDimitry Andric Printf("%s", str.data()); 5668d75effSDimitry Andric return; 5768d75effSDimitry Andric } 585f757f3fSDimitry Andric str.AppendF(" created by %s here:\n", 5968d75effSDimitry Andric AsanThreadIdAndName(context->parent_tid).c_str()); 6068d75effSDimitry Andric Printf("%s", str.data()); 6168d75effSDimitry Andric StackDepotGet(context->stack_id).Print(); 6268d75effSDimitry Andric // Recursively described parent thread if needed. 6368d75effSDimitry Andric if (flags()->print_full_thread_history) { 6468d75effSDimitry Andric AsanThreadContext *parent_context = 6568d75effSDimitry Andric GetThreadContextByTidLocked(context->parent_tid); 6668d75effSDimitry Andric DescribeThread(parent_context); 6768d75effSDimitry Andric } 6868d75effSDimitry Andric } 6968d75effSDimitry Andric 7068d75effSDimitry Andric // Shadow descriptions 7168d75effSDimitry Andric static bool GetShadowKind(uptr addr, ShadowKind *shadow_kind) { 7268d75effSDimitry Andric CHECK(!AddrIsInMem(addr)); 7368d75effSDimitry Andric if (AddrIsInShadowGap(addr)) { 7468d75effSDimitry Andric *shadow_kind = kShadowKindGap; 7568d75effSDimitry Andric } else if (AddrIsInHighShadow(addr)) { 7668d75effSDimitry Andric *shadow_kind = kShadowKindHigh; 7768d75effSDimitry Andric } else if (AddrIsInLowShadow(addr)) { 7868d75effSDimitry Andric *shadow_kind = kShadowKindLow; 7968d75effSDimitry Andric } else { 8068d75effSDimitry Andric return false; 8168d75effSDimitry Andric } 8268d75effSDimitry Andric return true; 8368d75effSDimitry Andric } 8468d75effSDimitry Andric 8568d75effSDimitry Andric bool DescribeAddressIfShadow(uptr addr) { 8668d75effSDimitry Andric ShadowAddressDescription descr; 8768d75effSDimitry Andric if (!GetShadowAddressInformation(addr, &descr)) return false; 8868d75effSDimitry Andric descr.Print(); 8968d75effSDimitry Andric return true; 9068d75effSDimitry Andric } 9168d75effSDimitry Andric 9268d75effSDimitry Andric bool GetShadowAddressInformation(uptr addr, ShadowAddressDescription *descr) { 9368d75effSDimitry Andric if (AddrIsInMem(addr)) return false; 9468d75effSDimitry Andric ShadowKind shadow_kind; 9568d75effSDimitry Andric if (!GetShadowKind(addr, &shadow_kind)) return false; 9668d75effSDimitry Andric if (shadow_kind != kShadowKindGap) descr->shadow_byte = *(u8 *)addr; 9768d75effSDimitry Andric descr->addr = addr; 9868d75effSDimitry Andric descr->kind = shadow_kind; 9968d75effSDimitry Andric return true; 10068d75effSDimitry Andric } 10168d75effSDimitry Andric 10268d75effSDimitry Andric // Heap descriptions 10368d75effSDimitry Andric static void GetAccessToHeapChunkInformation(ChunkAccess *descr, 10468d75effSDimitry Andric AsanChunkView chunk, uptr addr, 10568d75effSDimitry Andric uptr access_size) { 10668d75effSDimitry Andric descr->bad_addr = addr; 10768d75effSDimitry Andric if (chunk.AddrIsAtLeft(addr, access_size, &descr->offset)) { 10868d75effSDimitry Andric descr->access_type = kAccessTypeLeft; 10968d75effSDimitry Andric } else if (chunk.AddrIsAtRight(addr, access_size, &descr->offset)) { 11068d75effSDimitry Andric descr->access_type = kAccessTypeRight; 11168d75effSDimitry Andric if (descr->offset < 0) { 11268d75effSDimitry Andric descr->bad_addr -= descr->offset; 11368d75effSDimitry Andric descr->offset = 0; 11468d75effSDimitry Andric } 11568d75effSDimitry Andric } else if (chunk.AddrIsInside(addr, access_size, &descr->offset)) { 11668d75effSDimitry Andric descr->access_type = kAccessTypeInside; 11768d75effSDimitry Andric } else { 11868d75effSDimitry Andric descr->access_type = kAccessTypeUnknown; 11968d75effSDimitry Andric } 12068d75effSDimitry Andric descr->chunk_begin = chunk.Beg(); 12168d75effSDimitry Andric descr->chunk_size = chunk.UsedSize(); 12268d75effSDimitry Andric descr->user_requested_alignment = chunk.UserRequestedAlignment(); 12368d75effSDimitry Andric descr->alloc_type = chunk.GetAllocType(); 12468d75effSDimitry Andric } 12568d75effSDimitry Andric 12668d75effSDimitry Andric static void PrintHeapChunkAccess(uptr addr, const ChunkAccess &descr) { 12768d75effSDimitry Andric Decorator d; 128fe6060f1SDimitry Andric InternalScopedString str; 1295f757f3fSDimitry Andric str.Append(d.Location()); 13068d75effSDimitry Andric switch (descr.access_type) { 13168d75effSDimitry Andric case kAccessTypeLeft: 1325f757f3fSDimitry Andric str.AppendF("%p is located %zd bytes before", (void *)descr.bad_addr, 1335f757f3fSDimitry Andric descr.offset); 13468d75effSDimitry Andric break; 13568d75effSDimitry Andric case kAccessTypeRight: 1365f757f3fSDimitry Andric str.AppendF("%p is located %zd bytes after", (void *)descr.bad_addr, 1375f757f3fSDimitry Andric descr.offset); 13868d75effSDimitry Andric break; 13968d75effSDimitry Andric case kAccessTypeInside: 1405f757f3fSDimitry Andric str.AppendF("%p is located %zd bytes inside of", (void *)descr.bad_addr, 14168d75effSDimitry Andric descr.offset); 14268d75effSDimitry Andric break; 14368d75effSDimitry Andric case kAccessTypeUnknown: 1445f757f3fSDimitry Andric str.AppendF( 14568d75effSDimitry Andric "%p is located somewhere around (this is AddressSanitizer bug!)", 14668d75effSDimitry Andric (void *)descr.bad_addr); 14768d75effSDimitry Andric } 1485f757f3fSDimitry Andric str.AppendF(" %zu-byte region [%p,%p)\n", descr.chunk_size, 14968d75effSDimitry Andric (void *)descr.chunk_begin, 15068d75effSDimitry Andric (void *)(descr.chunk_begin + descr.chunk_size)); 1515f757f3fSDimitry Andric str.Append(d.Default()); 15268d75effSDimitry Andric Printf("%s", str.data()); 15368d75effSDimitry Andric } 15468d75effSDimitry Andric 15568d75effSDimitry Andric bool GetHeapAddressInformation(uptr addr, uptr access_size, 15668d75effSDimitry Andric HeapAddressDescription *descr) { 15768d75effSDimitry Andric AsanChunkView chunk = FindHeapChunkByAddress(addr); 15868d75effSDimitry Andric if (!chunk.IsValid()) { 15968d75effSDimitry Andric return false; 16068d75effSDimitry Andric } 16168d75effSDimitry Andric descr->addr = addr; 16268d75effSDimitry Andric GetAccessToHeapChunkInformation(&descr->chunk_access, chunk, addr, 16368d75effSDimitry Andric access_size); 16468d75effSDimitry Andric CHECK_NE(chunk.AllocTid(), kInvalidTid); 16568d75effSDimitry Andric descr->alloc_tid = chunk.AllocTid(); 16668d75effSDimitry Andric descr->alloc_stack_id = chunk.GetAllocStackId(); 16768d75effSDimitry Andric descr->free_tid = chunk.FreeTid(); 16868d75effSDimitry Andric if (descr->free_tid != kInvalidTid) 16968d75effSDimitry Andric descr->free_stack_id = chunk.GetFreeStackId(); 17068d75effSDimitry Andric return true; 17168d75effSDimitry Andric } 17268d75effSDimitry Andric 17368d75effSDimitry Andric static StackTrace GetStackTraceFromId(u32 id) { 17468d75effSDimitry Andric CHECK(id); 17568d75effSDimitry Andric StackTrace res = StackDepotGet(id); 17668d75effSDimitry Andric CHECK(res.trace); 17768d75effSDimitry Andric return res; 17868d75effSDimitry Andric } 17968d75effSDimitry Andric 18068d75effSDimitry Andric bool DescribeAddressIfHeap(uptr addr, uptr access_size) { 18168d75effSDimitry Andric HeapAddressDescription descr; 18268d75effSDimitry Andric if (!GetHeapAddressInformation(addr, access_size, &descr)) { 18368d75effSDimitry Andric Printf( 18468d75effSDimitry Andric "AddressSanitizer can not describe address in more detail " 18568d75effSDimitry Andric "(wild memory access suspected).\n"); 18668d75effSDimitry Andric return false; 18768d75effSDimitry Andric } 18868d75effSDimitry Andric descr.Print(); 18968d75effSDimitry Andric return true; 19068d75effSDimitry Andric } 19168d75effSDimitry Andric 19268d75effSDimitry Andric // Stack descriptions 19368d75effSDimitry Andric bool GetStackAddressInformation(uptr addr, uptr access_size, 19468d75effSDimitry Andric StackAddressDescription *descr) { 19568d75effSDimitry Andric AsanThread *t = FindThreadByStackAddress(addr); 19668d75effSDimitry Andric if (!t) return false; 19768d75effSDimitry Andric 19868d75effSDimitry Andric descr->addr = addr; 19968d75effSDimitry Andric descr->tid = t->tid(); 20068d75effSDimitry Andric // Try to fetch precise stack frame for this access. 20168d75effSDimitry Andric AsanThread::StackFrameAccess access; 20268d75effSDimitry Andric if (!t->GetStackFrameAccessByAddr(addr, &access)) { 20368d75effSDimitry Andric descr->frame_descr = nullptr; 20468d75effSDimitry Andric return true; 20568d75effSDimitry Andric } 20668d75effSDimitry Andric 20768d75effSDimitry Andric descr->offset = access.offset; 20868d75effSDimitry Andric descr->access_size = access_size; 20968d75effSDimitry Andric descr->frame_pc = access.frame_pc; 21068d75effSDimitry Andric descr->frame_descr = access.frame_descr; 21168d75effSDimitry Andric 21268d75effSDimitry Andric #if SANITIZER_PPC64V1 21368d75effSDimitry Andric // On PowerPC64 ELFv1, the address of a function actually points to a 21468d75effSDimitry Andric // three-doubleword data structure with the first field containing 21568d75effSDimitry Andric // the address of the function's code. 21668d75effSDimitry Andric descr->frame_pc = *reinterpret_cast<uptr *>(descr->frame_pc); 21768d75effSDimitry Andric #endif 21868d75effSDimitry Andric descr->frame_pc += 16; 21968d75effSDimitry Andric 22068d75effSDimitry Andric return true; 22168d75effSDimitry Andric } 22268d75effSDimitry Andric 22368d75effSDimitry Andric static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr, 22468d75effSDimitry Andric uptr access_size, uptr prev_var_end, 22568d75effSDimitry Andric uptr next_var_beg) { 22668d75effSDimitry Andric uptr var_end = var.beg + var.size; 22768d75effSDimitry Andric uptr addr_end = addr + access_size; 22868d75effSDimitry Andric const char *pos_descr = nullptr; 22968d75effSDimitry Andric // If the variable [var.beg, var_end) is the nearest variable to the 23068d75effSDimitry Andric // current memory access, indicate it in the log. 23168d75effSDimitry Andric if (addr >= var.beg) { 23268d75effSDimitry Andric if (addr_end <= var_end) 23368d75effSDimitry Andric pos_descr = "is inside"; // May happen if this is a use-after-return. 23468d75effSDimitry Andric else if (addr < var_end) 23568d75effSDimitry Andric pos_descr = "partially overflows"; 23668d75effSDimitry Andric else if (addr_end <= next_var_beg && 23768d75effSDimitry Andric next_var_beg - addr_end >= addr - var_end) 23868d75effSDimitry Andric pos_descr = "overflows"; 23968d75effSDimitry Andric } else { 24068d75effSDimitry Andric if (addr_end > var.beg) 24168d75effSDimitry Andric pos_descr = "partially underflows"; 24268d75effSDimitry Andric else if (addr >= prev_var_end && addr - prev_var_end >= var.beg - addr_end) 24368d75effSDimitry Andric pos_descr = "underflows"; 24468d75effSDimitry Andric } 245fe6060f1SDimitry Andric InternalScopedString str; 2465f757f3fSDimitry Andric str.AppendF(" [%zd, %zd)", var.beg, var_end); 24768d75effSDimitry Andric // Render variable name. 248*0fca6ea1SDimitry Andric str.Append(" '"); 24968d75effSDimitry Andric for (uptr i = 0; i < var.name_len; ++i) { 2505f757f3fSDimitry Andric str.AppendF("%c", var.name_pos[i]); 25168d75effSDimitry Andric } 252*0fca6ea1SDimitry Andric str.Append("'"); 25368d75effSDimitry Andric if (var.line > 0) { 2545f757f3fSDimitry Andric str.AppendF(" (line %zd)", var.line); 25568d75effSDimitry Andric } 25668d75effSDimitry Andric if (pos_descr) { 25768d75effSDimitry Andric Decorator d; 25868d75effSDimitry Andric // FIXME: we may want to also print the size of the access here, 25968d75effSDimitry Andric // but in case of accesses generated by memset it may be confusing. 2605f757f3fSDimitry Andric str.AppendF("%s <== Memory access at offset %zd %s this variable%s\n", 26168d75effSDimitry Andric d.Location(), addr, pos_descr, d.Default()); 26268d75effSDimitry Andric } else { 263*0fca6ea1SDimitry Andric str.Append("\n"); 26468d75effSDimitry Andric } 26568d75effSDimitry Andric Printf("%s", str.data()); 26668d75effSDimitry Andric } 26768d75effSDimitry Andric 26868d75effSDimitry Andric bool DescribeAddressIfStack(uptr addr, uptr access_size) { 26968d75effSDimitry Andric StackAddressDescription descr; 27068d75effSDimitry Andric if (!GetStackAddressInformation(addr, access_size, &descr)) return false; 27168d75effSDimitry Andric descr.Print(); 27268d75effSDimitry Andric return true; 27368d75effSDimitry Andric } 27468d75effSDimitry Andric 27568d75effSDimitry Andric // Global descriptions 27668d75effSDimitry Andric static void DescribeAddressRelativeToGlobal(uptr addr, uptr access_size, 27768d75effSDimitry Andric const __asan_global &g) { 278fe6060f1SDimitry Andric InternalScopedString str; 27968d75effSDimitry Andric Decorator d; 2805f757f3fSDimitry Andric str.Append(d.Location()); 28168d75effSDimitry Andric if (addr < g.beg) { 2825f757f3fSDimitry Andric str.AppendF("%p is located %zd bytes before", (void *)addr, g.beg - addr); 28368d75effSDimitry Andric } else if (addr + access_size > g.beg + g.size) { 28468d75effSDimitry Andric if (addr < g.beg + g.size) addr = g.beg + g.size; 2855f757f3fSDimitry Andric str.AppendF("%p is located %zd bytes after", (void *)addr, 28668d75effSDimitry Andric addr - (g.beg + g.size)); 28768d75effSDimitry Andric } else { 28868d75effSDimitry Andric // Can it happen? 2895f757f3fSDimitry Andric str.AppendF("%p is located %zd bytes inside of", (void *)addr, 2905f757f3fSDimitry Andric addr - g.beg); 29168d75effSDimitry Andric } 2925f757f3fSDimitry Andric str.AppendF(" global variable '%s' defined in '", 29368d75effSDimitry Andric MaybeDemangleGlobalName(g.name)); 2945f757f3fSDimitry Andric PrintGlobalLocation(&str, g, /*print_module_name=*/false); 295*0fca6ea1SDimitry Andric str.AppendF("' (%p) of size %zu\n", (void *)g.beg, g.size); 2965f757f3fSDimitry Andric str.Append(d.Default()); 29768d75effSDimitry Andric PrintGlobalNameIfASCII(&str, g); 29868d75effSDimitry Andric Printf("%s", str.data()); 29968d75effSDimitry Andric } 30068d75effSDimitry Andric 30168d75effSDimitry Andric bool GetGlobalAddressInformation(uptr addr, uptr access_size, 30268d75effSDimitry Andric GlobalAddressDescription *descr) { 30368d75effSDimitry Andric descr->addr = addr; 30468d75effSDimitry Andric int globals_num = GetGlobalsForAddress(addr, descr->globals, descr->reg_sites, 30568d75effSDimitry Andric ARRAY_SIZE(descr->globals)); 30668d75effSDimitry Andric descr->size = globals_num; 30768d75effSDimitry Andric descr->access_size = access_size; 30868d75effSDimitry Andric return globals_num != 0; 30968d75effSDimitry Andric } 31068d75effSDimitry Andric 31168d75effSDimitry Andric bool DescribeAddressIfGlobal(uptr addr, uptr access_size, 31268d75effSDimitry Andric const char *bug_type) { 31368d75effSDimitry Andric GlobalAddressDescription descr; 31468d75effSDimitry Andric if (!GetGlobalAddressInformation(addr, access_size, &descr)) return false; 31568d75effSDimitry Andric 31668d75effSDimitry Andric descr.Print(bug_type); 31768d75effSDimitry Andric return true; 31868d75effSDimitry Andric } 31968d75effSDimitry Andric 32068d75effSDimitry Andric void ShadowAddressDescription::Print() const { 321349cc55cSDimitry Andric Printf("Address %p is located in the %s area.\n", (void *)addr, 322349cc55cSDimitry Andric ShadowNames[kind]); 32368d75effSDimitry Andric } 32468d75effSDimitry Andric 32568d75effSDimitry Andric void GlobalAddressDescription::Print(const char *bug_type) const { 32668d75effSDimitry Andric for (int i = 0; i < size; i++) { 32768d75effSDimitry Andric DescribeAddressRelativeToGlobal(addr, access_size, globals[i]); 32868d75effSDimitry Andric if (bug_type && 32968d75effSDimitry Andric 0 == internal_strcmp(bug_type, "initialization-order-fiasco") && 33068d75effSDimitry Andric reg_sites[i]) { 33168d75effSDimitry Andric Printf(" registered at:\n"); 33268d75effSDimitry Andric StackDepotGet(reg_sites[i]).Print(); 33368d75effSDimitry Andric } 33468d75effSDimitry Andric } 33568d75effSDimitry Andric } 33668d75effSDimitry Andric 33768d75effSDimitry Andric bool GlobalAddressDescription::PointsInsideTheSameVariable( 33868d75effSDimitry Andric const GlobalAddressDescription &other) const { 33968d75effSDimitry Andric if (size == 0 || other.size == 0) return false; 34068d75effSDimitry Andric 34168d75effSDimitry Andric for (uptr i = 0; i < size; i++) { 34268d75effSDimitry Andric const __asan_global &a = globals[i]; 34368d75effSDimitry Andric for (uptr j = 0; j < other.size; j++) { 34468d75effSDimitry Andric const __asan_global &b = other.globals[j]; 34568d75effSDimitry Andric if (a.beg == b.beg && 34668d75effSDimitry Andric a.beg <= addr && 34768d75effSDimitry Andric b.beg <= other.addr && 34868d75effSDimitry Andric (addr + access_size) < (a.beg + a.size) && 34968d75effSDimitry Andric (other.addr + other.access_size) < (b.beg + b.size)) 35068d75effSDimitry Andric return true; 35168d75effSDimitry Andric } 35268d75effSDimitry Andric } 35368d75effSDimitry Andric 35468d75effSDimitry Andric return false; 35568d75effSDimitry Andric } 35668d75effSDimitry Andric 35768d75effSDimitry Andric void StackAddressDescription::Print() const { 35868d75effSDimitry Andric Decorator d; 35968d75effSDimitry Andric Printf("%s", d.Location()); 360349cc55cSDimitry Andric Printf("Address %p is located in stack of thread %s", (void *)addr, 36168d75effSDimitry Andric AsanThreadIdAndName(tid).c_str()); 36268d75effSDimitry Andric 36368d75effSDimitry Andric if (!frame_descr) { 36468d75effSDimitry Andric Printf("%s\n", d.Default()); 36568d75effSDimitry Andric return; 36668d75effSDimitry Andric } 36768d75effSDimitry Andric Printf(" at offset %zu in frame%s\n", offset, d.Default()); 36868d75effSDimitry Andric 36968d75effSDimitry Andric // Now we print the frame where the alloca has happened. 37068d75effSDimitry Andric // We print this frame as a stack trace with one element. 37168d75effSDimitry Andric // The symbolizer may print more than one frame if inlining was involved. 37268d75effSDimitry Andric // The frame numbers may be different than those in the stack trace printed 37368d75effSDimitry Andric // previously. That's unfortunate, but I have no better solution, 37468d75effSDimitry Andric // especially given that the alloca may be from entirely different place 37568d75effSDimitry Andric // (e.g. use-after-scope, or different thread's stack). 37668d75effSDimitry Andric Printf("%s", d.Default()); 37768d75effSDimitry Andric StackTrace alloca_stack(&frame_pc, 1); 37868d75effSDimitry Andric alloca_stack.Print(); 37968d75effSDimitry Andric 38068d75effSDimitry Andric InternalMmapVector<StackVarDescr> vars; 38168d75effSDimitry Andric vars.reserve(16); 38268d75effSDimitry Andric if (!ParseFrameDescription(frame_descr, &vars)) { 38368d75effSDimitry Andric Printf( 38468d75effSDimitry Andric "AddressSanitizer can't parse the stack frame " 38568d75effSDimitry Andric "descriptor: |%s|\n", 38668d75effSDimitry Andric frame_descr); 38768d75effSDimitry Andric // 'addr' is a stack address, so return true even if we can't parse frame 38868d75effSDimitry Andric return; 38968d75effSDimitry Andric } 39068d75effSDimitry Andric uptr n_objects = vars.size(); 39168d75effSDimitry Andric // Report the number of stack objects. 39268d75effSDimitry Andric Printf(" This frame has %zu object(s):\n", n_objects); 39368d75effSDimitry Andric 39468d75effSDimitry Andric // Report all objects in this frame. 39568d75effSDimitry Andric for (uptr i = 0; i < n_objects; i++) { 39668d75effSDimitry Andric uptr prev_var_end = i ? vars[i - 1].beg + vars[i - 1].size : 0; 39768d75effSDimitry Andric uptr next_var_beg = i + 1 < n_objects ? vars[i + 1].beg : ~(0UL); 39868d75effSDimitry Andric PrintAccessAndVarIntersection(vars[i], offset, access_size, prev_var_end, 39968d75effSDimitry Andric next_var_beg); 40068d75effSDimitry Andric } 40168d75effSDimitry Andric Printf( 40268d75effSDimitry Andric "HINT: this may be a false positive if your program uses " 40368d75effSDimitry Andric "some custom stack unwind mechanism, swapcontext or vfork\n"); 40468d75effSDimitry Andric if (SANITIZER_WINDOWS) 40568d75effSDimitry Andric Printf(" (longjmp, SEH and C++ exceptions *are* supported)\n"); 40668d75effSDimitry Andric else 40768d75effSDimitry Andric Printf(" (longjmp and C++ exceptions *are* supported)\n"); 40868d75effSDimitry Andric 40968d75effSDimitry Andric DescribeThread(GetThreadContextByTidLocked(tid)); 41068d75effSDimitry Andric } 41168d75effSDimitry Andric 41268d75effSDimitry Andric void HeapAddressDescription::Print() const { 41368d75effSDimitry Andric PrintHeapChunkAccess(addr, chunk_access); 41468d75effSDimitry Andric 41568d75effSDimitry Andric asanThreadRegistry().CheckLocked(); 41668d75effSDimitry Andric AsanThreadContext *alloc_thread = GetThreadContextByTidLocked(alloc_tid); 41768d75effSDimitry Andric StackTrace alloc_stack = GetStackTraceFromId(alloc_stack_id); 41868d75effSDimitry Andric 41968d75effSDimitry Andric Decorator d; 42068d75effSDimitry Andric AsanThreadContext *free_thread = nullptr; 42168d75effSDimitry Andric if (free_tid != kInvalidTid) { 42268d75effSDimitry Andric free_thread = GetThreadContextByTidLocked(free_tid); 42368d75effSDimitry Andric Printf("%sfreed by thread %s here:%s\n", d.Allocation(), 42468d75effSDimitry Andric AsanThreadIdAndName(free_thread).c_str(), d.Default()); 42568d75effSDimitry Andric StackTrace free_stack = GetStackTraceFromId(free_stack_id); 42668d75effSDimitry Andric free_stack.Print(); 42768d75effSDimitry Andric Printf("%spreviously allocated by thread %s here:%s\n", d.Allocation(), 42868d75effSDimitry Andric AsanThreadIdAndName(alloc_thread).c_str(), d.Default()); 42968d75effSDimitry Andric } else { 43068d75effSDimitry Andric Printf("%sallocated by thread %s here:%s\n", d.Allocation(), 43168d75effSDimitry Andric AsanThreadIdAndName(alloc_thread).c_str(), d.Default()); 43268d75effSDimitry Andric } 43368d75effSDimitry Andric alloc_stack.Print(); 43468d75effSDimitry Andric DescribeThread(GetCurrentThread()); 43568d75effSDimitry Andric if (free_thread) DescribeThread(free_thread); 43668d75effSDimitry Andric DescribeThread(alloc_thread); 43768d75effSDimitry Andric } 43868d75effSDimitry Andric 43968d75effSDimitry Andric AddressDescription::AddressDescription(uptr addr, uptr access_size, 44068d75effSDimitry Andric bool shouldLockThreadRegistry) { 44168d75effSDimitry Andric if (GetShadowAddressInformation(addr, &data.shadow)) { 44268d75effSDimitry Andric data.kind = kAddressKindShadow; 44368d75effSDimitry Andric return; 44468d75effSDimitry Andric } 44568d75effSDimitry Andric if (GetHeapAddressInformation(addr, access_size, &data.heap)) { 44668d75effSDimitry Andric data.kind = kAddressKindHeap; 44768d75effSDimitry Andric return; 44868d75effSDimitry Andric } 44968d75effSDimitry Andric 45068d75effSDimitry Andric bool isStackMemory = false; 45168d75effSDimitry Andric if (shouldLockThreadRegistry) { 45268d75effSDimitry Andric ThreadRegistryLock l(&asanThreadRegistry()); 45368d75effSDimitry Andric isStackMemory = GetStackAddressInformation(addr, access_size, &data.stack); 45468d75effSDimitry Andric } else { 45568d75effSDimitry Andric isStackMemory = GetStackAddressInformation(addr, access_size, &data.stack); 45668d75effSDimitry Andric } 45768d75effSDimitry Andric if (isStackMemory) { 45868d75effSDimitry Andric data.kind = kAddressKindStack; 45968d75effSDimitry Andric return; 46068d75effSDimitry Andric } 46168d75effSDimitry Andric 46268d75effSDimitry Andric if (GetGlobalAddressInformation(addr, access_size, &data.global)) { 46368d75effSDimitry Andric data.kind = kAddressKindGlobal; 46468d75effSDimitry Andric return; 46568d75effSDimitry Andric } 46668d75effSDimitry Andric data.kind = kAddressKindWild; 467fe6060f1SDimitry Andric data.wild.addr = addr; 468fe6060f1SDimitry Andric data.wild.access_size = access_size; 469fe6060f1SDimitry Andric } 470fe6060f1SDimitry Andric 471fe6060f1SDimitry Andric void WildAddressDescription::Print() const { 472fe6060f1SDimitry Andric Printf("Address %p is a wild pointer inside of access range of size %p.\n", 473349cc55cSDimitry Andric (void *)addr, (void *)access_size); 47468d75effSDimitry Andric } 47568d75effSDimitry Andric 47668d75effSDimitry Andric void PrintAddressDescription(uptr addr, uptr access_size, 47768d75effSDimitry Andric const char *bug_type) { 47868d75effSDimitry Andric ShadowAddressDescription shadow_descr; 47968d75effSDimitry Andric if (GetShadowAddressInformation(addr, &shadow_descr)) { 48068d75effSDimitry Andric shadow_descr.Print(); 48168d75effSDimitry Andric return; 48268d75effSDimitry Andric } 48368d75effSDimitry Andric 48468d75effSDimitry Andric GlobalAddressDescription global_descr; 48568d75effSDimitry Andric if (GetGlobalAddressInformation(addr, access_size, &global_descr)) { 48668d75effSDimitry Andric global_descr.Print(bug_type); 48768d75effSDimitry Andric return; 48868d75effSDimitry Andric } 48968d75effSDimitry Andric 49068d75effSDimitry Andric StackAddressDescription stack_descr; 49168d75effSDimitry Andric if (GetStackAddressInformation(addr, access_size, &stack_descr)) { 49268d75effSDimitry Andric stack_descr.Print(); 49368d75effSDimitry Andric return; 49468d75effSDimitry Andric } 49568d75effSDimitry Andric 49668d75effSDimitry Andric HeapAddressDescription heap_descr; 49768d75effSDimitry Andric if (GetHeapAddressInformation(addr, access_size, &heap_descr)) { 49868d75effSDimitry Andric heap_descr.Print(); 49968d75effSDimitry Andric return; 50068d75effSDimitry Andric } 50168d75effSDimitry Andric 50268d75effSDimitry Andric // We exhausted our possibilities. Bail out. 50368d75effSDimitry Andric Printf( 50468d75effSDimitry Andric "AddressSanitizer can not describe address in more detail " 50568d75effSDimitry Andric "(wild memory access suspected).\n"); 50668d75effSDimitry Andric } 50768d75effSDimitry Andric } // namespace __asan 508