xref: /openbsd-src/gnu/llvm/compiler-rt/lib/asan/asan_descriptions.cpp (revision 810390e339a5425391477d5d41c78d7cab2424ac)
13cab2bb3Spatrick //===-- asan_descriptions.cpp -----------------------------------*- C++ -*-===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick //
93cab2bb3Spatrick // This file is a part of AddressSanitizer, an address sanity checker.
103cab2bb3Spatrick //
113cab2bb3Spatrick // ASan functions for getting information about an address and/or printing it.
123cab2bb3Spatrick //===----------------------------------------------------------------------===//
133cab2bb3Spatrick 
143cab2bb3Spatrick #include "asan_descriptions.h"
153cab2bb3Spatrick #include "asan_mapping.h"
163cab2bb3Spatrick #include "asan_report.h"
173cab2bb3Spatrick #include "asan_stack.h"
183cab2bb3Spatrick #include "sanitizer_common/sanitizer_stackdepot.h"
193cab2bb3Spatrick 
203cab2bb3Spatrick namespace __asan {
213cab2bb3Spatrick 
AsanThreadIdAndName(AsanThreadContext * t)223cab2bb3Spatrick AsanThreadIdAndName::AsanThreadIdAndName(AsanThreadContext *t) {
233cab2bb3Spatrick   Init(t->tid, t->name);
243cab2bb3Spatrick }
253cab2bb3Spatrick 
AsanThreadIdAndName(u32 tid)263cab2bb3Spatrick AsanThreadIdAndName::AsanThreadIdAndName(u32 tid) {
273cab2bb3Spatrick   if (tid == kInvalidTid) {
283cab2bb3Spatrick     Init(tid, "");
293cab2bb3Spatrick   } else {
303cab2bb3Spatrick     asanThreadRegistry().CheckLocked();
313cab2bb3Spatrick     AsanThreadContext *t = GetThreadContextByTidLocked(tid);
323cab2bb3Spatrick     Init(tid, t->name);
333cab2bb3Spatrick   }
343cab2bb3Spatrick }
353cab2bb3Spatrick 
Init(u32 tid,const char * tname)363cab2bb3Spatrick void AsanThreadIdAndName::Init(u32 tid, const char *tname) {
373cab2bb3Spatrick   int len = internal_snprintf(name, sizeof(name), "T%d", tid);
383cab2bb3Spatrick   CHECK(((unsigned int)len) < sizeof(name));
393cab2bb3Spatrick   if (tname[0] != '\0')
403cab2bb3Spatrick     internal_snprintf(&name[len], sizeof(name) - len, " (%s)", tname);
413cab2bb3Spatrick }
423cab2bb3Spatrick 
DescribeThread(AsanThreadContext * context)433cab2bb3Spatrick void DescribeThread(AsanThreadContext *context) {
443cab2bb3Spatrick   CHECK(context);
453cab2bb3Spatrick   asanThreadRegistry().CheckLocked();
463cab2bb3Spatrick   // No need to announce the main thread.
47d89ec533Spatrick   if (context->tid == kMainTid || context->announced) {
483cab2bb3Spatrick     return;
493cab2bb3Spatrick   }
503cab2bb3Spatrick   context->announced = true;
51d89ec533Spatrick   InternalScopedString str;
523cab2bb3Spatrick   str.append("Thread %s", AsanThreadIdAndName(context).c_str());
533cab2bb3Spatrick   if (context->parent_tid == kInvalidTid) {
543cab2bb3Spatrick     str.append(" created by unknown thread\n");
553cab2bb3Spatrick     Printf("%s", str.data());
563cab2bb3Spatrick     return;
573cab2bb3Spatrick   }
583cab2bb3Spatrick   str.append(" created by %s here:\n",
593cab2bb3Spatrick              AsanThreadIdAndName(context->parent_tid).c_str());
603cab2bb3Spatrick   Printf("%s", str.data());
613cab2bb3Spatrick   StackDepotGet(context->stack_id).Print();
623cab2bb3Spatrick   // Recursively described parent thread if needed.
633cab2bb3Spatrick   if (flags()->print_full_thread_history) {
643cab2bb3Spatrick     AsanThreadContext *parent_context =
653cab2bb3Spatrick         GetThreadContextByTidLocked(context->parent_tid);
663cab2bb3Spatrick     DescribeThread(parent_context);
673cab2bb3Spatrick   }
683cab2bb3Spatrick }
693cab2bb3Spatrick 
703cab2bb3Spatrick // Shadow descriptions
GetShadowKind(uptr addr,ShadowKind * shadow_kind)713cab2bb3Spatrick static bool GetShadowKind(uptr addr, ShadowKind *shadow_kind) {
723cab2bb3Spatrick   CHECK(!AddrIsInMem(addr));
733cab2bb3Spatrick   if (AddrIsInShadowGap(addr)) {
743cab2bb3Spatrick     *shadow_kind = kShadowKindGap;
753cab2bb3Spatrick   } else if (AddrIsInHighShadow(addr)) {
763cab2bb3Spatrick     *shadow_kind = kShadowKindHigh;
773cab2bb3Spatrick   } else if (AddrIsInLowShadow(addr)) {
783cab2bb3Spatrick     *shadow_kind = kShadowKindLow;
793cab2bb3Spatrick   } else {
803cab2bb3Spatrick     return false;
813cab2bb3Spatrick   }
823cab2bb3Spatrick   return true;
833cab2bb3Spatrick }
843cab2bb3Spatrick 
DescribeAddressIfShadow(uptr addr)853cab2bb3Spatrick bool DescribeAddressIfShadow(uptr addr) {
863cab2bb3Spatrick   ShadowAddressDescription descr;
873cab2bb3Spatrick   if (!GetShadowAddressInformation(addr, &descr)) return false;
883cab2bb3Spatrick   descr.Print();
893cab2bb3Spatrick   return true;
903cab2bb3Spatrick }
913cab2bb3Spatrick 
GetShadowAddressInformation(uptr addr,ShadowAddressDescription * descr)923cab2bb3Spatrick bool GetShadowAddressInformation(uptr addr, ShadowAddressDescription *descr) {
933cab2bb3Spatrick   if (AddrIsInMem(addr)) return false;
943cab2bb3Spatrick   ShadowKind shadow_kind;
953cab2bb3Spatrick   if (!GetShadowKind(addr, &shadow_kind)) return false;
963cab2bb3Spatrick   if (shadow_kind != kShadowKindGap) descr->shadow_byte = *(u8 *)addr;
973cab2bb3Spatrick   descr->addr = addr;
983cab2bb3Spatrick   descr->kind = shadow_kind;
993cab2bb3Spatrick   return true;
1003cab2bb3Spatrick }
1013cab2bb3Spatrick 
1023cab2bb3Spatrick // Heap descriptions
GetAccessToHeapChunkInformation(ChunkAccess * descr,AsanChunkView chunk,uptr addr,uptr access_size)1033cab2bb3Spatrick static void GetAccessToHeapChunkInformation(ChunkAccess *descr,
1043cab2bb3Spatrick                                             AsanChunkView chunk, uptr addr,
1053cab2bb3Spatrick                                             uptr access_size) {
1063cab2bb3Spatrick   descr->bad_addr = addr;
1073cab2bb3Spatrick   if (chunk.AddrIsAtLeft(addr, access_size, &descr->offset)) {
1083cab2bb3Spatrick     descr->access_type = kAccessTypeLeft;
1093cab2bb3Spatrick   } else if (chunk.AddrIsAtRight(addr, access_size, &descr->offset)) {
1103cab2bb3Spatrick     descr->access_type = kAccessTypeRight;
1113cab2bb3Spatrick     if (descr->offset < 0) {
1123cab2bb3Spatrick       descr->bad_addr -= descr->offset;
1133cab2bb3Spatrick       descr->offset = 0;
1143cab2bb3Spatrick     }
1153cab2bb3Spatrick   } else if (chunk.AddrIsInside(addr, access_size, &descr->offset)) {
1163cab2bb3Spatrick     descr->access_type = kAccessTypeInside;
1173cab2bb3Spatrick   } else {
1183cab2bb3Spatrick     descr->access_type = kAccessTypeUnknown;
1193cab2bb3Spatrick   }
1203cab2bb3Spatrick   descr->chunk_begin = chunk.Beg();
1213cab2bb3Spatrick   descr->chunk_size = chunk.UsedSize();
1223cab2bb3Spatrick   descr->user_requested_alignment = chunk.UserRequestedAlignment();
1233cab2bb3Spatrick   descr->alloc_type = chunk.GetAllocType();
1243cab2bb3Spatrick }
1253cab2bb3Spatrick 
PrintHeapChunkAccess(uptr addr,const ChunkAccess & descr)1263cab2bb3Spatrick static void PrintHeapChunkAccess(uptr addr, const ChunkAccess &descr) {
1273cab2bb3Spatrick   Decorator d;
128d89ec533Spatrick   InternalScopedString str;
1293cab2bb3Spatrick   str.append("%s", d.Location());
1303cab2bb3Spatrick   switch (descr.access_type) {
1313cab2bb3Spatrick     case kAccessTypeLeft:
132*810390e3Srobert       str.append("%p is located %zd bytes before",
1333cab2bb3Spatrick                  (void *)descr.bad_addr, descr.offset);
1343cab2bb3Spatrick       break;
1353cab2bb3Spatrick     case kAccessTypeRight:
136*810390e3Srobert       str.append("%p is located %zd bytes after",
1373cab2bb3Spatrick                  (void *)descr.bad_addr, descr.offset);
1383cab2bb3Spatrick       break;
1393cab2bb3Spatrick     case kAccessTypeInside:
1403cab2bb3Spatrick       str.append("%p is located %zd bytes inside of", (void *)descr.bad_addr,
1413cab2bb3Spatrick                  descr.offset);
1423cab2bb3Spatrick       break;
1433cab2bb3Spatrick     case kAccessTypeUnknown:
1443cab2bb3Spatrick       str.append(
1453cab2bb3Spatrick           "%p is located somewhere around (this is AddressSanitizer bug!)",
1463cab2bb3Spatrick           (void *)descr.bad_addr);
1473cab2bb3Spatrick   }
1483cab2bb3Spatrick   str.append(" %zu-byte region [%p,%p)\n", descr.chunk_size,
1493cab2bb3Spatrick              (void *)descr.chunk_begin,
1503cab2bb3Spatrick              (void *)(descr.chunk_begin + descr.chunk_size));
1513cab2bb3Spatrick   str.append("%s", d.Default());
1523cab2bb3Spatrick   Printf("%s", str.data());
1533cab2bb3Spatrick }
1543cab2bb3Spatrick 
GetHeapAddressInformation(uptr addr,uptr access_size,HeapAddressDescription * descr)1553cab2bb3Spatrick bool GetHeapAddressInformation(uptr addr, uptr access_size,
1563cab2bb3Spatrick                                HeapAddressDescription *descr) {
1573cab2bb3Spatrick   AsanChunkView chunk = FindHeapChunkByAddress(addr);
1583cab2bb3Spatrick   if (!chunk.IsValid()) {
1593cab2bb3Spatrick     return false;
1603cab2bb3Spatrick   }
1613cab2bb3Spatrick   descr->addr = addr;
1623cab2bb3Spatrick   GetAccessToHeapChunkInformation(&descr->chunk_access, chunk, addr,
1633cab2bb3Spatrick                                   access_size);
1643cab2bb3Spatrick   CHECK_NE(chunk.AllocTid(), kInvalidTid);
1653cab2bb3Spatrick   descr->alloc_tid = chunk.AllocTid();
1663cab2bb3Spatrick   descr->alloc_stack_id = chunk.GetAllocStackId();
1673cab2bb3Spatrick   descr->free_tid = chunk.FreeTid();
1683cab2bb3Spatrick   if (descr->free_tid != kInvalidTid)
1693cab2bb3Spatrick     descr->free_stack_id = chunk.GetFreeStackId();
1703cab2bb3Spatrick   return true;
1713cab2bb3Spatrick }
1723cab2bb3Spatrick 
GetStackTraceFromId(u32 id)1733cab2bb3Spatrick static StackTrace GetStackTraceFromId(u32 id) {
1743cab2bb3Spatrick   CHECK(id);
1753cab2bb3Spatrick   StackTrace res = StackDepotGet(id);
1763cab2bb3Spatrick   CHECK(res.trace);
1773cab2bb3Spatrick   return res;
1783cab2bb3Spatrick }
1793cab2bb3Spatrick 
DescribeAddressIfHeap(uptr addr,uptr access_size)1803cab2bb3Spatrick bool DescribeAddressIfHeap(uptr addr, uptr access_size) {
1813cab2bb3Spatrick   HeapAddressDescription descr;
1823cab2bb3Spatrick   if (!GetHeapAddressInformation(addr, access_size, &descr)) {
1833cab2bb3Spatrick     Printf(
1843cab2bb3Spatrick         "AddressSanitizer can not describe address in more detail "
1853cab2bb3Spatrick         "(wild memory access suspected).\n");
1863cab2bb3Spatrick     return false;
1873cab2bb3Spatrick   }
1883cab2bb3Spatrick   descr.Print();
1893cab2bb3Spatrick   return true;
1903cab2bb3Spatrick }
1913cab2bb3Spatrick 
1923cab2bb3Spatrick // Stack descriptions
GetStackAddressInformation(uptr addr,uptr access_size,StackAddressDescription * descr)1933cab2bb3Spatrick bool GetStackAddressInformation(uptr addr, uptr access_size,
1943cab2bb3Spatrick                                 StackAddressDescription *descr) {
1953cab2bb3Spatrick   AsanThread *t = FindThreadByStackAddress(addr);
1963cab2bb3Spatrick   if (!t) return false;
1973cab2bb3Spatrick 
1983cab2bb3Spatrick   descr->addr = addr;
1993cab2bb3Spatrick   descr->tid = t->tid();
2003cab2bb3Spatrick   // Try to fetch precise stack frame for this access.
2013cab2bb3Spatrick   AsanThread::StackFrameAccess access;
2023cab2bb3Spatrick   if (!t->GetStackFrameAccessByAddr(addr, &access)) {
2033cab2bb3Spatrick     descr->frame_descr = nullptr;
2043cab2bb3Spatrick     return true;
2053cab2bb3Spatrick   }
2063cab2bb3Spatrick 
2073cab2bb3Spatrick   descr->offset = access.offset;
2083cab2bb3Spatrick   descr->access_size = access_size;
2093cab2bb3Spatrick   descr->frame_pc = access.frame_pc;
2103cab2bb3Spatrick   descr->frame_descr = access.frame_descr;
2113cab2bb3Spatrick 
2123cab2bb3Spatrick #if SANITIZER_PPC64V1
2133cab2bb3Spatrick   // On PowerPC64 ELFv1, the address of a function actually points to a
2143cab2bb3Spatrick   // three-doubleword data structure with the first field containing
2153cab2bb3Spatrick   // the address of the function's code.
2163cab2bb3Spatrick   descr->frame_pc = *reinterpret_cast<uptr *>(descr->frame_pc);
2173cab2bb3Spatrick #endif
2183cab2bb3Spatrick   descr->frame_pc += 16;
2193cab2bb3Spatrick 
2203cab2bb3Spatrick   return true;
2213cab2bb3Spatrick }
2223cab2bb3Spatrick 
PrintAccessAndVarIntersection(const StackVarDescr & var,uptr addr,uptr access_size,uptr prev_var_end,uptr next_var_beg)2233cab2bb3Spatrick static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr,
2243cab2bb3Spatrick                                           uptr access_size, uptr prev_var_end,
2253cab2bb3Spatrick                                           uptr next_var_beg) {
2263cab2bb3Spatrick   uptr var_end = var.beg + var.size;
2273cab2bb3Spatrick   uptr addr_end = addr + access_size;
2283cab2bb3Spatrick   const char *pos_descr = nullptr;
2293cab2bb3Spatrick   // If the variable [var.beg, var_end) is the nearest variable to the
2303cab2bb3Spatrick   // current memory access, indicate it in the log.
2313cab2bb3Spatrick   if (addr >= var.beg) {
2323cab2bb3Spatrick     if (addr_end <= var_end)
2333cab2bb3Spatrick       pos_descr = "is inside";  // May happen if this is a use-after-return.
2343cab2bb3Spatrick     else if (addr < var_end)
2353cab2bb3Spatrick       pos_descr = "partially overflows";
2363cab2bb3Spatrick     else if (addr_end <= next_var_beg &&
2373cab2bb3Spatrick              next_var_beg - addr_end >= addr - var_end)
2383cab2bb3Spatrick       pos_descr = "overflows";
2393cab2bb3Spatrick   } else {
2403cab2bb3Spatrick     if (addr_end > var.beg)
2413cab2bb3Spatrick       pos_descr = "partially underflows";
2423cab2bb3Spatrick     else if (addr >= prev_var_end && addr - prev_var_end >= var.beg - addr_end)
2433cab2bb3Spatrick       pos_descr = "underflows";
2443cab2bb3Spatrick   }
245d89ec533Spatrick   InternalScopedString str;
2463cab2bb3Spatrick   str.append("    [%zd, %zd)", var.beg, var_end);
2473cab2bb3Spatrick   // Render variable name.
2483cab2bb3Spatrick   str.append(" '");
2493cab2bb3Spatrick   for (uptr i = 0; i < var.name_len; ++i) {
2503cab2bb3Spatrick     str.append("%c", var.name_pos[i]);
2513cab2bb3Spatrick   }
2523cab2bb3Spatrick   str.append("'");
2533cab2bb3Spatrick   if (var.line > 0) {
254*810390e3Srobert     str.append(" (line %zd)", var.line);
2553cab2bb3Spatrick   }
2563cab2bb3Spatrick   if (pos_descr) {
2573cab2bb3Spatrick     Decorator d;
2583cab2bb3Spatrick     // FIXME: we may want to also print the size of the access here,
2593cab2bb3Spatrick     // but in case of accesses generated by memset it may be confusing.
2603cab2bb3Spatrick     str.append("%s <== Memory access at offset %zd %s this variable%s\n",
2613cab2bb3Spatrick                d.Location(), addr, pos_descr, d.Default());
2623cab2bb3Spatrick   } else {
2633cab2bb3Spatrick     str.append("\n");
2643cab2bb3Spatrick   }
2653cab2bb3Spatrick   Printf("%s", str.data());
2663cab2bb3Spatrick }
2673cab2bb3Spatrick 
DescribeAddressIfStack(uptr addr,uptr access_size)2683cab2bb3Spatrick bool DescribeAddressIfStack(uptr addr, uptr access_size) {
2693cab2bb3Spatrick   StackAddressDescription descr;
2703cab2bb3Spatrick   if (!GetStackAddressInformation(addr, access_size, &descr)) return false;
2713cab2bb3Spatrick   descr.Print();
2723cab2bb3Spatrick   return true;
2733cab2bb3Spatrick }
2743cab2bb3Spatrick 
2753cab2bb3Spatrick // Global descriptions
DescribeAddressRelativeToGlobal(uptr addr,uptr access_size,const __asan_global & g)2763cab2bb3Spatrick static void DescribeAddressRelativeToGlobal(uptr addr, uptr access_size,
2773cab2bb3Spatrick                                             const __asan_global &g) {
278d89ec533Spatrick   InternalScopedString str;
2793cab2bb3Spatrick   Decorator d;
2803cab2bb3Spatrick   str.append("%s", d.Location());
2813cab2bb3Spatrick   if (addr < g.beg) {
282*810390e3Srobert     str.append("%p is located %zd bytes before", (void *)addr,
2833cab2bb3Spatrick                g.beg - addr);
2843cab2bb3Spatrick   } else if (addr + access_size > g.beg + g.size) {
2853cab2bb3Spatrick     if (addr < g.beg + g.size) addr = g.beg + g.size;
286*810390e3Srobert     str.append("%p is located %zd bytes after", (void *)addr,
2873cab2bb3Spatrick                addr - (g.beg + g.size));
2883cab2bb3Spatrick   } else {
2893cab2bb3Spatrick     // Can it happen?
290*810390e3Srobert     str.append("%p is located %zd bytes inside of", (void *)addr, addr - g.beg);
2913cab2bb3Spatrick   }
292*810390e3Srobert   str.append(" global variable '%s' defined in '",
2933cab2bb3Spatrick              MaybeDemangleGlobalName(g.name));
2943cab2bb3Spatrick   PrintGlobalLocation(&str, g);
2953cab2bb3Spatrick   str.append("' (0x%zx) of size %zu\n", g.beg, g.size);
2963cab2bb3Spatrick   str.append("%s", d.Default());
2973cab2bb3Spatrick   PrintGlobalNameIfASCII(&str, g);
2983cab2bb3Spatrick   Printf("%s", str.data());
2993cab2bb3Spatrick }
3003cab2bb3Spatrick 
GetGlobalAddressInformation(uptr addr,uptr access_size,GlobalAddressDescription * descr)3013cab2bb3Spatrick bool GetGlobalAddressInformation(uptr addr, uptr access_size,
3023cab2bb3Spatrick                                  GlobalAddressDescription *descr) {
3033cab2bb3Spatrick   descr->addr = addr;
3043cab2bb3Spatrick   int globals_num = GetGlobalsForAddress(addr, descr->globals, descr->reg_sites,
3053cab2bb3Spatrick                                          ARRAY_SIZE(descr->globals));
3063cab2bb3Spatrick   descr->size = globals_num;
3073cab2bb3Spatrick   descr->access_size = access_size;
3083cab2bb3Spatrick   return globals_num != 0;
3093cab2bb3Spatrick }
3103cab2bb3Spatrick 
DescribeAddressIfGlobal(uptr addr,uptr access_size,const char * bug_type)3113cab2bb3Spatrick bool DescribeAddressIfGlobal(uptr addr, uptr access_size,
3123cab2bb3Spatrick                              const char *bug_type) {
3133cab2bb3Spatrick   GlobalAddressDescription descr;
3143cab2bb3Spatrick   if (!GetGlobalAddressInformation(addr, access_size, &descr)) return false;
3153cab2bb3Spatrick 
3163cab2bb3Spatrick   descr.Print(bug_type);
3173cab2bb3Spatrick   return true;
3183cab2bb3Spatrick }
3193cab2bb3Spatrick 
Print() const3203cab2bb3Spatrick void ShadowAddressDescription::Print() const {
321*810390e3Srobert   Printf("Address %p is located in the %s area.\n", (void *)addr,
322*810390e3Srobert          ShadowNames[kind]);
3233cab2bb3Spatrick }
3243cab2bb3Spatrick 
Print(const char * bug_type) const3253cab2bb3Spatrick void GlobalAddressDescription::Print(const char *bug_type) const {
3263cab2bb3Spatrick   for (int i = 0; i < size; i++) {
3273cab2bb3Spatrick     DescribeAddressRelativeToGlobal(addr, access_size, globals[i]);
3283cab2bb3Spatrick     if (bug_type &&
3293cab2bb3Spatrick         0 == internal_strcmp(bug_type, "initialization-order-fiasco") &&
3303cab2bb3Spatrick         reg_sites[i]) {
3313cab2bb3Spatrick       Printf("  registered at:\n");
3323cab2bb3Spatrick       StackDepotGet(reg_sites[i]).Print();
3333cab2bb3Spatrick     }
3343cab2bb3Spatrick   }
3353cab2bb3Spatrick }
3363cab2bb3Spatrick 
PointsInsideTheSameVariable(const GlobalAddressDescription & other) const3373cab2bb3Spatrick bool GlobalAddressDescription::PointsInsideTheSameVariable(
3383cab2bb3Spatrick     const GlobalAddressDescription &other) const {
3393cab2bb3Spatrick   if (size == 0 || other.size == 0) return false;
3403cab2bb3Spatrick 
3413cab2bb3Spatrick   for (uptr i = 0; i < size; i++) {
3423cab2bb3Spatrick     const __asan_global &a = globals[i];
3433cab2bb3Spatrick     for (uptr j = 0; j < other.size; j++) {
3443cab2bb3Spatrick       const __asan_global &b = other.globals[j];
3453cab2bb3Spatrick       if (a.beg == b.beg &&
3463cab2bb3Spatrick           a.beg <= addr &&
3473cab2bb3Spatrick           b.beg <= other.addr &&
3483cab2bb3Spatrick           (addr + access_size) < (a.beg + a.size) &&
3493cab2bb3Spatrick           (other.addr + other.access_size) < (b.beg + b.size))
3503cab2bb3Spatrick         return true;
3513cab2bb3Spatrick     }
3523cab2bb3Spatrick   }
3533cab2bb3Spatrick 
3543cab2bb3Spatrick   return false;
3553cab2bb3Spatrick }
3563cab2bb3Spatrick 
Print() const3573cab2bb3Spatrick void StackAddressDescription::Print() const {
3583cab2bb3Spatrick   Decorator d;
3593cab2bb3Spatrick   Printf("%s", d.Location());
360*810390e3Srobert   Printf("Address %p is located in stack of thread %s", (void *)addr,
3613cab2bb3Spatrick          AsanThreadIdAndName(tid).c_str());
3623cab2bb3Spatrick 
3633cab2bb3Spatrick   if (!frame_descr) {
3643cab2bb3Spatrick     Printf("%s\n", d.Default());
3653cab2bb3Spatrick     return;
3663cab2bb3Spatrick   }
3673cab2bb3Spatrick   Printf(" at offset %zu in frame%s\n", offset, d.Default());
3683cab2bb3Spatrick 
3693cab2bb3Spatrick   // Now we print the frame where the alloca has happened.
3703cab2bb3Spatrick   // We print this frame as a stack trace with one element.
3713cab2bb3Spatrick   // The symbolizer may print more than one frame if inlining was involved.
3723cab2bb3Spatrick   // The frame numbers may be different than those in the stack trace printed
3733cab2bb3Spatrick   // previously. That's unfortunate, but I have no better solution,
3743cab2bb3Spatrick   // especially given that the alloca may be from entirely different place
3753cab2bb3Spatrick   // (e.g. use-after-scope, or different thread's stack).
3763cab2bb3Spatrick   Printf("%s", d.Default());
3773cab2bb3Spatrick   StackTrace alloca_stack(&frame_pc, 1);
3783cab2bb3Spatrick   alloca_stack.Print();
3793cab2bb3Spatrick 
3803cab2bb3Spatrick   InternalMmapVector<StackVarDescr> vars;
3813cab2bb3Spatrick   vars.reserve(16);
3823cab2bb3Spatrick   if (!ParseFrameDescription(frame_descr, &vars)) {
3833cab2bb3Spatrick     Printf(
3843cab2bb3Spatrick         "AddressSanitizer can't parse the stack frame "
3853cab2bb3Spatrick         "descriptor: |%s|\n",
3863cab2bb3Spatrick         frame_descr);
3873cab2bb3Spatrick     // 'addr' is a stack address, so return true even if we can't parse frame
3883cab2bb3Spatrick     return;
3893cab2bb3Spatrick   }
3903cab2bb3Spatrick   uptr n_objects = vars.size();
3913cab2bb3Spatrick   // Report the number of stack objects.
3923cab2bb3Spatrick   Printf("  This frame has %zu object(s):\n", n_objects);
3933cab2bb3Spatrick 
3943cab2bb3Spatrick   // Report all objects in this frame.
3953cab2bb3Spatrick   for (uptr i = 0; i < n_objects; i++) {
3963cab2bb3Spatrick     uptr prev_var_end = i ? vars[i - 1].beg + vars[i - 1].size : 0;
3973cab2bb3Spatrick     uptr next_var_beg = i + 1 < n_objects ? vars[i + 1].beg : ~(0UL);
3983cab2bb3Spatrick     PrintAccessAndVarIntersection(vars[i], offset, access_size, prev_var_end,
3993cab2bb3Spatrick                                   next_var_beg);
4003cab2bb3Spatrick   }
4013cab2bb3Spatrick   Printf(
4023cab2bb3Spatrick       "HINT: this may be a false positive if your program uses "
4033cab2bb3Spatrick       "some custom stack unwind mechanism, swapcontext or vfork\n");
4043cab2bb3Spatrick   if (SANITIZER_WINDOWS)
4053cab2bb3Spatrick     Printf("      (longjmp, SEH and C++ exceptions *are* supported)\n");
4063cab2bb3Spatrick   else
4073cab2bb3Spatrick     Printf("      (longjmp and C++ exceptions *are* supported)\n");
4083cab2bb3Spatrick 
4093cab2bb3Spatrick   DescribeThread(GetThreadContextByTidLocked(tid));
4103cab2bb3Spatrick }
4113cab2bb3Spatrick 
Print() const4123cab2bb3Spatrick void HeapAddressDescription::Print() const {
4133cab2bb3Spatrick   PrintHeapChunkAccess(addr, chunk_access);
4143cab2bb3Spatrick 
4153cab2bb3Spatrick   asanThreadRegistry().CheckLocked();
4163cab2bb3Spatrick   AsanThreadContext *alloc_thread = GetThreadContextByTidLocked(alloc_tid);
4173cab2bb3Spatrick   StackTrace alloc_stack = GetStackTraceFromId(alloc_stack_id);
4183cab2bb3Spatrick 
4193cab2bb3Spatrick   Decorator d;
4203cab2bb3Spatrick   AsanThreadContext *free_thread = nullptr;
4213cab2bb3Spatrick   if (free_tid != kInvalidTid) {
4223cab2bb3Spatrick     free_thread = GetThreadContextByTidLocked(free_tid);
4233cab2bb3Spatrick     Printf("%sfreed by thread %s here:%s\n", d.Allocation(),
4243cab2bb3Spatrick            AsanThreadIdAndName(free_thread).c_str(), d.Default());
4253cab2bb3Spatrick     StackTrace free_stack = GetStackTraceFromId(free_stack_id);
4263cab2bb3Spatrick     free_stack.Print();
4273cab2bb3Spatrick     Printf("%spreviously allocated by thread %s here:%s\n", d.Allocation(),
4283cab2bb3Spatrick            AsanThreadIdAndName(alloc_thread).c_str(), d.Default());
4293cab2bb3Spatrick   } else {
4303cab2bb3Spatrick     Printf("%sallocated by thread %s here:%s\n", d.Allocation(),
4313cab2bb3Spatrick            AsanThreadIdAndName(alloc_thread).c_str(), d.Default());
4323cab2bb3Spatrick   }
4333cab2bb3Spatrick   alloc_stack.Print();
4343cab2bb3Spatrick   DescribeThread(GetCurrentThread());
4353cab2bb3Spatrick   if (free_thread) DescribeThread(free_thread);
4363cab2bb3Spatrick   DescribeThread(alloc_thread);
4373cab2bb3Spatrick }
4383cab2bb3Spatrick 
AddressDescription(uptr addr,uptr access_size,bool shouldLockThreadRegistry)4393cab2bb3Spatrick AddressDescription::AddressDescription(uptr addr, uptr access_size,
4403cab2bb3Spatrick                                        bool shouldLockThreadRegistry) {
4413cab2bb3Spatrick   if (GetShadowAddressInformation(addr, &data.shadow)) {
4423cab2bb3Spatrick     data.kind = kAddressKindShadow;
4433cab2bb3Spatrick     return;
4443cab2bb3Spatrick   }
4453cab2bb3Spatrick   if (GetHeapAddressInformation(addr, access_size, &data.heap)) {
4463cab2bb3Spatrick     data.kind = kAddressKindHeap;
4473cab2bb3Spatrick     return;
4483cab2bb3Spatrick   }
4493cab2bb3Spatrick 
4503cab2bb3Spatrick   bool isStackMemory = false;
4513cab2bb3Spatrick   if (shouldLockThreadRegistry) {
4523cab2bb3Spatrick     ThreadRegistryLock l(&asanThreadRegistry());
4533cab2bb3Spatrick     isStackMemory = GetStackAddressInformation(addr, access_size, &data.stack);
4543cab2bb3Spatrick   } else {
4553cab2bb3Spatrick     isStackMemory = GetStackAddressInformation(addr, access_size, &data.stack);
4563cab2bb3Spatrick   }
4573cab2bb3Spatrick   if (isStackMemory) {
4583cab2bb3Spatrick     data.kind = kAddressKindStack;
4593cab2bb3Spatrick     return;
4603cab2bb3Spatrick   }
4613cab2bb3Spatrick 
4623cab2bb3Spatrick   if (GetGlobalAddressInformation(addr, access_size, &data.global)) {
4633cab2bb3Spatrick     data.kind = kAddressKindGlobal;
4643cab2bb3Spatrick     return;
4653cab2bb3Spatrick   }
4663cab2bb3Spatrick   data.kind = kAddressKindWild;
467d89ec533Spatrick   data.wild.addr = addr;
468d89ec533Spatrick   data.wild.access_size = access_size;
469d89ec533Spatrick }
470d89ec533Spatrick 
Print() const471d89ec533Spatrick void WildAddressDescription::Print() const {
472d89ec533Spatrick   Printf("Address %p is a wild pointer inside of access range of size %p.\n",
473*810390e3Srobert          (void *)addr, (void *)access_size);
4743cab2bb3Spatrick }
4753cab2bb3Spatrick 
PrintAddressDescription(uptr addr,uptr access_size,const char * bug_type)4763cab2bb3Spatrick void PrintAddressDescription(uptr addr, uptr access_size,
4773cab2bb3Spatrick                              const char *bug_type) {
4783cab2bb3Spatrick   ShadowAddressDescription shadow_descr;
4793cab2bb3Spatrick   if (GetShadowAddressInformation(addr, &shadow_descr)) {
4803cab2bb3Spatrick     shadow_descr.Print();
4813cab2bb3Spatrick     return;
4823cab2bb3Spatrick   }
4833cab2bb3Spatrick 
4843cab2bb3Spatrick   GlobalAddressDescription global_descr;
4853cab2bb3Spatrick   if (GetGlobalAddressInformation(addr, access_size, &global_descr)) {
4863cab2bb3Spatrick     global_descr.Print(bug_type);
4873cab2bb3Spatrick     return;
4883cab2bb3Spatrick   }
4893cab2bb3Spatrick 
4903cab2bb3Spatrick   StackAddressDescription stack_descr;
4913cab2bb3Spatrick   if (GetStackAddressInformation(addr, access_size, &stack_descr)) {
4923cab2bb3Spatrick     stack_descr.Print();
4933cab2bb3Spatrick     return;
4943cab2bb3Spatrick   }
4953cab2bb3Spatrick 
4963cab2bb3Spatrick   HeapAddressDescription heap_descr;
4973cab2bb3Spatrick   if (GetHeapAddressInformation(addr, access_size, &heap_descr)) {
4983cab2bb3Spatrick     heap_descr.Print();
4993cab2bb3Spatrick     return;
5003cab2bb3Spatrick   }
5013cab2bb3Spatrick 
5023cab2bb3Spatrick   // We exhausted our possibilities. Bail out.
5033cab2bb3Spatrick   Printf(
5043cab2bb3Spatrick       "AddressSanitizer can not describe address in more detail "
5053cab2bb3Spatrick       "(wild memory access suspected).\n");
5063cab2bb3Spatrick }
5073cab2bb3Spatrick }  // namespace __asan
508