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