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 
AsanThreadIdAndName(AsanThreadContext * t)2268d75effSDimitry Andric AsanThreadIdAndName::AsanThreadIdAndName(AsanThreadContext *t) {
2368d75effSDimitry Andric   Init(t->tid, t->name);
2468d75effSDimitry Andric }
2568d75effSDimitry Andric 
AsanThreadIdAndName(u32 tid)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 
Init(u32 tid,const char * tname)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 
DescribeThread(AsanThreadContext * context)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;
52*5f757f3fSDimitry Andric   str.AppendF("Thread %s", AsanThreadIdAndName(context).c_str());
5368d75effSDimitry Andric   if (context->parent_tid == kInvalidTid) {
54*5f757f3fSDimitry Andric     str.Append(" created by unknown thread\n");
5568d75effSDimitry Andric     Printf("%s", str.data());
5668d75effSDimitry Andric     return;
5768d75effSDimitry Andric   }
58*5f757f3fSDimitry 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
GetShadowKind(uptr addr,ShadowKind * shadow_kind)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 
DescribeAddressIfShadow(uptr addr)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 
GetShadowAddressInformation(uptr addr,ShadowAddressDescription * descr)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
GetAccessToHeapChunkInformation(ChunkAccess * descr,AsanChunkView chunk,uptr addr,uptr access_size)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 
PrintHeapChunkAccess(uptr addr,const ChunkAccess & descr)12668d75effSDimitry Andric static void PrintHeapChunkAccess(uptr addr, const ChunkAccess &descr) {
12768d75effSDimitry Andric   Decorator d;
128fe6060f1SDimitry Andric   InternalScopedString str;
129*5f757f3fSDimitry Andric   str.Append(d.Location());
13068d75effSDimitry Andric   switch (descr.access_type) {
13168d75effSDimitry Andric     case kAccessTypeLeft:
132*5f757f3fSDimitry Andric       str.AppendF("%p is located %zd bytes before", (void *)descr.bad_addr,
133*5f757f3fSDimitry Andric                   descr.offset);
13468d75effSDimitry Andric       break;
13568d75effSDimitry Andric     case kAccessTypeRight:
136*5f757f3fSDimitry Andric       str.AppendF("%p is located %zd bytes after", (void *)descr.bad_addr,
137*5f757f3fSDimitry Andric                   descr.offset);
13868d75effSDimitry Andric       break;
13968d75effSDimitry Andric     case kAccessTypeInside:
140*5f757f3fSDimitry 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:
144*5f757f3fSDimitry Andric       str.AppendF(
14568d75effSDimitry Andric           "%p is located somewhere around (this is AddressSanitizer bug!)",
14668d75effSDimitry Andric           (void *)descr.bad_addr);
14768d75effSDimitry Andric   }
148*5f757f3fSDimitry 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));
151*5f757f3fSDimitry Andric   str.Append(d.Default());
15268d75effSDimitry Andric   Printf("%s", str.data());
15368d75effSDimitry Andric }
15468d75effSDimitry Andric 
GetHeapAddressInformation(uptr addr,uptr access_size,HeapAddressDescription * descr)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 
GetStackTraceFromId(u32 id)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 
DescribeAddressIfHeap(uptr addr,uptr access_size)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
GetStackAddressInformation(uptr addr,uptr access_size,StackAddressDescription * descr)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 
PrintAccessAndVarIntersection(const StackVarDescr & var,uptr addr,uptr access_size,uptr prev_var_end,uptr next_var_beg)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;
246*5f757f3fSDimitry Andric   str.AppendF("    [%zd, %zd)", var.beg, var_end);
24768d75effSDimitry Andric   // Render variable name.
248*5f757f3fSDimitry Andric   str.AppendF(" '");
24968d75effSDimitry Andric   for (uptr i = 0; i < var.name_len; ++i) {
250*5f757f3fSDimitry Andric     str.AppendF("%c", var.name_pos[i]);
25168d75effSDimitry Andric   }
252*5f757f3fSDimitry Andric   str.AppendF("'");
25368d75effSDimitry Andric   if (var.line > 0) {
254*5f757f3fSDimitry 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.
260*5f757f3fSDimitry 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*5f757f3fSDimitry Andric     str.AppendF("\n");
26468d75effSDimitry Andric   }
26568d75effSDimitry Andric   Printf("%s", str.data());
26668d75effSDimitry Andric }
26768d75effSDimitry Andric 
DescribeAddressIfStack(uptr addr,uptr access_size)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
DescribeAddressRelativeToGlobal(uptr addr,uptr access_size,const __asan_global & g)27668d75effSDimitry Andric static void DescribeAddressRelativeToGlobal(uptr addr, uptr access_size,
27768d75effSDimitry Andric                                             const __asan_global &g) {
278fe6060f1SDimitry Andric   InternalScopedString str;
27968d75effSDimitry Andric   Decorator d;
280*5f757f3fSDimitry Andric   str.Append(d.Location());
28168d75effSDimitry Andric   if (addr < g.beg) {
282*5f757f3fSDimitry 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;
285*5f757f3fSDimitry 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?
289*5f757f3fSDimitry Andric     str.AppendF("%p is located %zd bytes inside of", (void *)addr,
290*5f757f3fSDimitry Andric                 addr - g.beg);
29168d75effSDimitry Andric   }
292*5f757f3fSDimitry Andric   str.AppendF(" global variable '%s' defined in '",
29368d75effSDimitry Andric               MaybeDemangleGlobalName(g.name));
294*5f757f3fSDimitry Andric   PrintGlobalLocation(&str, g, /*print_module_name=*/false);
295*5f757f3fSDimitry Andric   str.AppendF("' (0x%zx) of size %zu\n", g.beg, g.size);
296*5f757f3fSDimitry Andric   str.Append(d.Default());
29768d75effSDimitry Andric   PrintGlobalNameIfASCII(&str, g);
29868d75effSDimitry Andric   Printf("%s", str.data());
29968d75effSDimitry Andric }
30068d75effSDimitry Andric 
GetGlobalAddressInformation(uptr addr,uptr access_size,GlobalAddressDescription * descr)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 
DescribeAddressIfGlobal(uptr addr,uptr access_size,const char * bug_type)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 
Print() const32068d75effSDimitry 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 
Print(const char * bug_type) const32568d75effSDimitry 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 
PointsInsideTheSameVariable(const GlobalAddressDescription & other) const33768d75effSDimitry 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 
Print() const35768d75effSDimitry 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 
Print() const41268d75effSDimitry 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 
AddressDescription(uptr addr,uptr access_size,bool shouldLockThreadRegistry)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 
Print() const471fe6060f1SDimitry 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 
PrintAddressDescription(uptr addr,uptr access_size,const char * bug_type)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