1//===-- asan_report.cc ----------------------------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file is a part of AddressSanitizer, an address sanity checker.
11//
12// This file contains error reporting code.
13//===----------------------------------------------------------------------===//
14
15#include "asan_flags.h"
16#include "asan_internal.h"
17#include "asan_mapping.h"
18#include "asan_report.h"
19#include "asan_stack.h"
20#include "asan_thread.h"
21#include "sanitizer_common/sanitizer_common.h"
22#include "sanitizer_common/sanitizer_flags.h"
23#include "sanitizer_common/sanitizer_report_decorator.h"
24#include "sanitizer_common/sanitizer_stackdepot.h"
25#include "sanitizer_common/sanitizer_symbolizer.h"
26
27namespace __asan {
28
29// -------------------- User-specified callbacks ----------------- {{{1
30static void (*error_report_callback)(const char*);
31static char *error_message_buffer = nullptr;
32static uptr error_message_buffer_pos = 0;
33static BlockingMutex error_message_buf_mutex(LINKER_INITIALIZED);
34static const unsigned kAsanBuggyPcPoolSize = 25;
35static __sanitizer::atomic_uintptr_t AsanBuggyPcPool[kAsanBuggyPcPoolSize];
36
37struct ReportData {
38  uptr pc;
39  uptr sp;
40  uptr bp;
41  uptr addr;
42  bool is_write;
43  uptr access_size;
44  const char *description;
45};
46
47static bool report_happened = false;
48static ReportData report_data = {};
49
50void AppendToErrorMessageBuffer(const char *buffer) {
51  BlockingMutexLock l(&error_message_buf_mutex);
52  if (!error_message_buffer) {
53    error_message_buffer =
54      (char*)MmapOrDieQuietly(kErrorMessageBufferSize, __func__);
55    error_message_buffer_pos = 0;
56  }
57  uptr length = internal_strlen(buffer);
58  RAW_CHECK(kErrorMessageBufferSize >= error_message_buffer_pos);
59  uptr remaining = kErrorMessageBufferSize - error_message_buffer_pos;
60  internal_strncpy(error_message_buffer + error_message_buffer_pos,
61                   buffer, remaining);
62  error_message_buffer[kErrorMessageBufferSize - 1] = '\0';
63  // FIXME: reallocate the buffer instead of truncating the message.
64  error_message_buffer_pos += Min(remaining, length);
65}
66
67// ---------------------- Decorator ------------------------------ {{{1
68class Decorator: public __sanitizer::SanitizerCommonDecorator {
69 public:
70  Decorator() : SanitizerCommonDecorator() { }
71  const char *Access()     { return Blue(); }
72  const char *EndAccess()  { return Default(); }
73  const char *Location()   { return Green(); }
74  const char *EndLocation() { return Default(); }
75  const char *Allocation()  { return Magenta(); }
76  const char *EndAllocation()  { return Default(); }
77
78  const char *ShadowByte(u8 byte) {
79    switch (byte) {
80      case kAsanHeapLeftRedzoneMagic:
81      case kAsanHeapRightRedzoneMagic:
82      case kAsanArrayCookieMagic:
83        return Red();
84      case kAsanHeapFreeMagic:
85        return Magenta();
86      case kAsanStackLeftRedzoneMagic:
87      case kAsanStackMidRedzoneMagic:
88      case kAsanStackRightRedzoneMagic:
89      case kAsanStackPartialRedzoneMagic:
90        return Red();
91      case kAsanStackAfterReturnMagic:
92        return Magenta();
93      case kAsanInitializationOrderMagic:
94        return Cyan();
95      case kAsanUserPoisonedMemoryMagic:
96      case kAsanContiguousContainerOOBMagic:
97      case kAsanAllocaLeftMagic:
98      case kAsanAllocaRightMagic:
99        return Blue();
100      case kAsanStackUseAfterScopeMagic:
101        return Magenta();
102      case kAsanGlobalRedzoneMagic:
103        return Red();
104      case kAsanInternalHeapMagic:
105        return Yellow();
106      case kAsanIntraObjectRedzone:
107        return Yellow();
108      default:
109        return Default();
110    }
111  }
112  const char *EndShadowByte() { return Default(); }
113  const char *MemoryByte() { return Magenta(); }
114  const char *EndMemoryByte() { return Default(); }
115};
116
117// ---------------------- Helper functions ----------------------- {{{1
118
119static void PrintMemoryByte(InternalScopedString *str, const char *before,
120    u8 byte, bool in_shadow, const char *after = "\n") {
121  Decorator d;
122  str->append("%s%s%x%x%s%s", before,
123              in_shadow ? d.ShadowByte(byte) : d.MemoryByte(),
124              byte >> 4, byte & 15,
125              in_shadow ? d.EndShadowByte() : d.EndMemoryByte(), after);
126}
127
128static void PrintShadowByte(InternalScopedString *str, const char *before,
129    u8 byte, const char *after = "\n") {
130  PrintMemoryByte(str, before, byte, /*in_shadow*/true, after);
131}
132
133static void PrintShadowBytes(InternalScopedString *str, const char *before,
134                             u8 *bytes, u8 *guilty, uptr n) {
135  Decorator d;
136  if (before) str->append("%s%p:", before, bytes);
137  for (uptr i = 0; i < n; i++) {
138    u8 *p = bytes + i;
139    const char *before =
140        p == guilty ? "[" : (p - 1 == guilty && i != 0) ? "" : " ";
141    const char *after = p == guilty ? "]" : "";
142    PrintShadowByte(str, before, *p, after);
143  }
144  str->append("\n");
145}
146
147static void PrintLegend(InternalScopedString *str) {
148  str->append(
149      "Shadow byte legend (one shadow byte represents %d "
150      "application bytes):\n",
151      (int)SHADOW_GRANULARITY);
152  PrintShadowByte(str, "  Addressable:           ", 0);
153  str->append("  Partially addressable: ");
154  for (u8 i = 1; i < SHADOW_GRANULARITY; i++) PrintShadowByte(str, "", i, " ");
155  str->append("\n");
156  PrintShadowByte(str, "  Heap left redzone:       ",
157                  kAsanHeapLeftRedzoneMagic);
158  PrintShadowByte(str, "  Heap right redzone:      ",
159                  kAsanHeapRightRedzoneMagic);
160  PrintShadowByte(str, "  Freed heap region:       ", kAsanHeapFreeMagic);
161  PrintShadowByte(str, "  Stack left redzone:      ",
162                  kAsanStackLeftRedzoneMagic);
163  PrintShadowByte(str, "  Stack mid redzone:       ",
164                  kAsanStackMidRedzoneMagic);
165  PrintShadowByte(str, "  Stack right redzone:     ",
166                  kAsanStackRightRedzoneMagic);
167  PrintShadowByte(str, "  Stack partial redzone:   ",
168                  kAsanStackPartialRedzoneMagic);
169  PrintShadowByte(str, "  Stack after return:      ",
170                  kAsanStackAfterReturnMagic);
171  PrintShadowByte(str, "  Stack use after scope:   ",
172                  kAsanStackUseAfterScopeMagic);
173  PrintShadowByte(str, "  Global redzone:          ", kAsanGlobalRedzoneMagic);
174  PrintShadowByte(str, "  Global init order:       ",
175                  kAsanInitializationOrderMagic);
176  PrintShadowByte(str, "  Poisoned by user:        ",
177                  kAsanUserPoisonedMemoryMagic);
178  PrintShadowByte(str, "  Container overflow:      ",
179                  kAsanContiguousContainerOOBMagic);
180  PrintShadowByte(str, "  Array cookie:            ",
181                  kAsanArrayCookieMagic);
182  PrintShadowByte(str, "  Intra object redzone:    ",
183                  kAsanIntraObjectRedzone);
184  PrintShadowByte(str, "  ASan internal:           ", kAsanInternalHeapMagic);
185  PrintShadowByte(str, "  Left alloca redzone:     ", kAsanAllocaLeftMagic);
186  PrintShadowByte(str, "  Right alloca redzone:    ", kAsanAllocaRightMagic);
187}
188
189void MaybeDumpInstructionBytes(uptr pc) {
190  if (!flags()->dump_instruction_bytes || (pc < GetPageSizeCached()))
191    return;
192  InternalScopedString str(1024);
193  str.append("First 16 instruction bytes at pc: ");
194  if (IsAccessibleMemoryRange(pc, 16)) {
195    for (int i = 0; i < 16; ++i) {
196      PrintMemoryByte(&str, "", ((u8 *)pc)[i], /*in_shadow*/false, " ");
197    }
198    str.append("\n");
199  } else {
200    str.append("unaccessible\n");
201  }
202  Report("%s", str.data());
203}
204
205static void PrintShadowMemoryForAddress(uptr addr) {
206  if (!AddrIsInMem(addr)) return;
207  uptr shadow_addr = MemToShadow(addr);
208  const uptr n_bytes_per_row = 16;
209  uptr aligned_shadow = shadow_addr & ~(n_bytes_per_row - 1);
210  InternalScopedString str(4096 * 8);
211  str.append("Shadow bytes around the buggy address:\n");
212  for (int i = -5; i <= 5; i++) {
213    const char *prefix = (i == 0) ? "=>" : "  ";
214    PrintShadowBytes(&str, prefix, (u8 *)(aligned_shadow + i * n_bytes_per_row),
215                     (u8 *)shadow_addr, n_bytes_per_row);
216  }
217  if (flags()->print_legend) PrintLegend(&str);
218  Printf("%s", str.data());
219}
220
221static void PrintZoneForPointer(uptr ptr, uptr zone_ptr,
222                                const char *zone_name) {
223  if (zone_ptr) {
224    if (zone_name) {
225      Printf("malloc_zone_from_ptr(%p) = %p, which is %s\n",
226                 ptr, zone_ptr, zone_name);
227    } else {
228      Printf("malloc_zone_from_ptr(%p) = %p, which doesn't have a name\n",
229                 ptr, zone_ptr);
230    }
231  } else {
232    Printf("malloc_zone_from_ptr(%p) = 0\n", ptr);
233  }
234}
235
236static void DescribeThread(AsanThread *t) {
237  if (t)
238    DescribeThread(t->context());
239}
240
241// ---------------------- Address Descriptions ------------------- {{{1
242
243static bool IsASCII(unsigned char c) {
244  return /*0x00 <= c &&*/ c <= 0x7F;
245}
246
247static const char *MaybeDemangleGlobalName(const char *name) {
248  // We can spoil names of globals with C linkage, so use an heuristic
249  // approach to check if the name should be demangled.
250  bool should_demangle = false;
251  if (name[0] == '_' && name[1] == 'Z')
252    should_demangle = true;
253  else if (SANITIZER_WINDOWS && name[0] == '\01' && name[1] == '?')
254    should_demangle = true;
255
256  return should_demangle ? Symbolizer::GetOrInit()->Demangle(name) : name;
257}
258
259// Check if the global is a zero-terminated ASCII string. If so, print it.
260static void PrintGlobalNameIfASCII(InternalScopedString *str,
261                                   const __asan_global &g) {
262  for (uptr p = g.beg; p < g.beg + g.size - 1; p++) {
263    unsigned char c = *(unsigned char*)p;
264    if (c == '\0' || !IsASCII(c)) return;
265  }
266  if (*(char*)(g.beg + g.size - 1) != '\0') return;
267  str->append("  '%s' is ascii string '%s'\n", MaybeDemangleGlobalName(g.name),
268              (char *)g.beg);
269}
270
271static const char *GlobalFilename(const __asan_global &g) {
272  const char *res = g.module_name;
273  // Prefer the filename from source location, if is available.
274  if (g.location)
275    res = g.location->filename;
276  CHECK(res);
277  return res;
278}
279
280static void PrintGlobalLocation(InternalScopedString *str,
281                                const __asan_global &g) {
282  str->append("%s", GlobalFilename(g));
283  if (!g.location)
284    return;
285  if (g.location->line_no)
286    str->append(":%d", g.location->line_no);
287  if (g.location->column_no)
288    str->append(":%d", g.location->column_no);
289}
290
291static void DescribeAddressRelativeToGlobal(uptr addr, uptr size,
292                                            const __asan_global &g) {
293  InternalScopedString str(4096);
294  Decorator d;
295  str.append("%s", d.Location());
296  if (addr < g.beg) {
297    str.append("%p is located %zd bytes to the left", (void *)addr,
298               g.beg - addr);
299  } else if (addr + size > g.beg + g.size) {
300    if (addr < g.beg + g.size)
301      addr = g.beg + g.size;
302    str.append("%p is located %zd bytes to the right", (void *)addr,
303               addr - (g.beg + g.size));
304  } else {
305    // Can it happen?
306    str.append("%p is located %zd bytes inside", (void *)addr, addr - g.beg);
307  }
308  str.append(" of global variable '%s' defined in '",
309             MaybeDemangleGlobalName(g.name));
310  PrintGlobalLocation(&str, g);
311  str.append("' (0x%zx) of size %zu\n", g.beg, g.size);
312  str.append("%s", d.EndLocation());
313  PrintGlobalNameIfASCII(&str, g);
314  Printf("%s", str.data());
315}
316
317static bool DescribeAddressIfGlobal(uptr addr, uptr size,
318                                    const char *bug_type) {
319  // Assume address is close to at most four globals.
320  const int kMaxGlobalsInReport = 4;
321  __asan_global globals[kMaxGlobalsInReport];
322  u32 reg_sites[kMaxGlobalsInReport];
323  int globals_num =
324      GetGlobalsForAddress(addr, globals, reg_sites, ARRAY_SIZE(globals));
325  if (globals_num == 0)
326    return false;
327  for (int i = 0; i < globals_num; i++) {
328    DescribeAddressRelativeToGlobal(addr, size, globals[i]);
329    if (0 == internal_strcmp(bug_type, "initialization-order-fiasco") &&
330        reg_sites[i]) {
331      Printf("  registered at:\n");
332      StackDepotGet(reg_sites[i]).Print();
333    }
334  }
335  return true;
336}
337
338bool DescribeAddressIfShadow(uptr addr, AddressDescription *descr, bool print) {
339  if (AddrIsInMem(addr))
340    return false;
341  const char *area_type = nullptr;
342  if (AddrIsInShadowGap(addr)) area_type = "shadow gap";
343  else if (AddrIsInHighShadow(addr)) area_type = "high shadow";
344  else if (AddrIsInLowShadow(addr)) area_type = "low shadow";
345  if (area_type != nullptr) {
346    if (print) {
347      Printf("Address %p is located in the %s area.\n", addr, area_type);
348    } else {
349      CHECK(descr);
350      descr->region_kind = area_type;
351    }
352    return true;
353  }
354  CHECK(0 && "Address is not in memory and not in shadow?");
355  return false;
356}
357
358// Return " (thread_name) " or an empty string if the name is empty.
359const char *ThreadNameWithParenthesis(AsanThreadContext *t, char buff[],
360                                      uptr buff_len) {
361  const char *name = t->name;
362  if (name[0] == '\0') return "";
363  buff[0] = 0;
364  internal_strncat(buff, " (", 3);
365  internal_strncat(buff, name, buff_len - 4);
366  internal_strncat(buff, ")", 2);
367  return buff;
368}
369
370const char *ThreadNameWithParenthesis(u32 tid, char buff[],
371                                      uptr buff_len) {
372  if (tid == kInvalidTid) return "";
373  asanThreadRegistry().CheckLocked();
374  AsanThreadContext *t = GetThreadContextByTidLocked(tid);
375  return ThreadNameWithParenthesis(t, buff, buff_len);
376}
377
378static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr,
379                                          uptr access_size, uptr prev_var_end,
380                                          uptr next_var_beg) {
381  uptr var_end = var.beg + var.size;
382  uptr addr_end = addr + access_size;
383  const char *pos_descr = nullptr;
384  // If the variable [var.beg, var_end) is the nearest variable to the
385  // current memory access, indicate it in the log.
386  if (addr >= var.beg) {
387    if (addr_end <= var_end)
388      pos_descr = "is inside";  // May happen if this is a use-after-return.
389    else if (addr < var_end)
390      pos_descr = "partially overflows";
391    else if (addr_end <= next_var_beg &&
392             next_var_beg - addr_end >= addr - var_end)
393      pos_descr = "overflows";
394  } else {
395    if (addr_end > var.beg)
396      pos_descr = "partially underflows";
397    else if (addr >= prev_var_end &&
398             addr - prev_var_end >= var.beg - addr_end)
399      pos_descr = "underflows";
400  }
401  InternalScopedString str(1024);
402  str.append("    [%zd, %zd)", var.beg, var_end);
403  // Render variable name.
404  str.append(" '");
405  for (uptr i = 0; i < var.name_len; ++i) {
406    str.append("%c", var.name_pos[i]);
407  }
408  str.append("'");
409  if (pos_descr) {
410    Decorator d;
411    // FIXME: we may want to also print the size of the access here,
412    // but in case of accesses generated by memset it may be confusing.
413    str.append("%s <== Memory access at offset %zd %s this variable%s\n",
414               d.Location(), addr, pos_descr, d.EndLocation());
415  } else {
416    str.append("\n");
417  }
418  Printf("%s", str.data());
419}
420
421bool ParseFrameDescription(const char *frame_descr,
422                           InternalMmapVector<StackVarDescr> *vars) {
423  CHECK(frame_descr);
424  char *p;
425  // This string is created by the compiler and has the following form:
426  // "n alloc_1 alloc_2 ... alloc_n"
427  // where alloc_i looks like "offset size len ObjectName".
428  uptr n_objects = (uptr)internal_simple_strtoll(frame_descr, &p, 10);
429  if (n_objects == 0)
430    return false;
431
432  for (uptr i = 0; i < n_objects; i++) {
433    uptr beg  = (uptr)internal_simple_strtoll(p, &p, 10);
434    uptr size = (uptr)internal_simple_strtoll(p, &p, 10);
435    uptr len  = (uptr)internal_simple_strtoll(p, &p, 10);
436    if (beg == 0 || size == 0 || *p != ' ') {
437      return false;
438    }
439    p++;
440    StackVarDescr var = {beg, size, p, len};
441    vars->push_back(var);
442    p += len;
443  }
444
445  return true;
446}
447
448bool DescribeAddressIfStack(uptr addr, uptr access_size) {
449  AsanThread *t = FindThreadByStackAddress(addr);
450  if (!t) return false;
451
452  Decorator d;
453  char tname[128];
454  Printf("%s", d.Location());
455  Printf("Address %p is located in stack of thread T%d%s", addr, t->tid(),
456         ThreadNameWithParenthesis(t->tid(), tname, sizeof(tname)));
457
458  // Try to fetch precise stack frame for this access.
459  AsanThread::StackFrameAccess access;
460  if (!t->GetStackFrameAccessByAddr(addr, &access)) {
461    Printf("%s\n", d.EndLocation());
462    return true;
463  }
464  Printf(" at offset %zu in frame%s\n", access.offset, d.EndLocation());
465
466  // Now we print the frame where the alloca has happened.
467  // We print this frame as a stack trace with one element.
468  // The symbolizer may print more than one frame if inlining was involved.
469  // The frame numbers may be different than those in the stack trace printed
470  // previously. That's unfortunate, but I have no better solution,
471  // especially given that the alloca may be from entirely different place
472  // (e.g. use-after-scope, or different thread's stack).
473#if defined(__powerpc64__) && defined(__BIG_ENDIAN__)
474  // On PowerPC64 ELFv1, the address of a function actually points to a
475  // three-doubleword data structure with the first field containing
476  // the address of the function's code.
477  access.frame_pc = *reinterpret_cast<uptr *>(access.frame_pc);
478#endif
479  access.frame_pc += 16;
480  Printf("%s", d.EndLocation());
481  StackTrace alloca_stack(&access.frame_pc, 1);
482  alloca_stack.Print();
483
484  InternalMmapVector<StackVarDescr> vars(16);
485  if (!ParseFrameDescription(access.frame_descr, &vars)) {
486    Printf("AddressSanitizer can't parse the stack frame "
487           "descriptor: |%s|\n", access.frame_descr);
488    // 'addr' is a stack address, so return true even if we can't parse frame
489    return true;
490  }
491  uptr n_objects = vars.size();
492  // Report the number of stack objects.
493  Printf("  This frame has %zu object(s):\n", n_objects);
494
495  // Report all objects in this frame.
496  for (uptr i = 0; i < n_objects; i++) {
497    uptr prev_var_end = i ? vars[i - 1].beg + vars[i - 1].size : 0;
498    uptr next_var_beg = i + 1 < n_objects ? vars[i + 1].beg : ~(0UL);
499    PrintAccessAndVarIntersection(vars[i], access.offset, access_size,
500                                  prev_var_end, next_var_beg);
501  }
502  Printf("HINT: this may be a false positive if your program uses "
503         "some custom stack unwind mechanism or swapcontext\n");
504  if (SANITIZER_WINDOWS)
505    Printf("      (longjmp, SEH and C++ exceptions *are* supported)\n");
506  else
507    Printf("      (longjmp and C++ exceptions *are* supported)\n");
508
509  DescribeThread(t);
510  return true;
511}
512
513static void DescribeAccessToHeapChunk(AsanChunkView chunk, uptr addr,
514                                      uptr access_size) {
515  sptr offset;
516  Decorator d;
517  InternalScopedString str(4096);
518  str.append("%s", d.Location());
519  if (chunk.AddrIsAtLeft(addr, access_size, &offset)) {
520    str.append("%p is located %zd bytes to the left of", (void *)addr, offset);
521  } else if (chunk.AddrIsAtRight(addr, access_size, &offset)) {
522    if (offset < 0) {
523      addr -= offset;
524      offset = 0;
525    }
526    str.append("%p is located %zd bytes to the right of", (void *)addr, offset);
527  } else if (chunk.AddrIsInside(addr, access_size, &offset)) {
528    str.append("%p is located %zd bytes inside of", (void*)addr, offset);
529  } else {
530    str.append("%p is located somewhere around (this is AddressSanitizer bug!)",
531               (void *)addr);
532  }
533  str.append(" %zu-byte region [%p,%p)\n", chunk.UsedSize(),
534             (void *)(chunk.Beg()), (void *)(chunk.End()));
535  str.append("%s", d.EndLocation());
536  Printf("%s", str.data());
537}
538
539void DescribeHeapAddress(uptr addr, uptr access_size) {
540  AsanChunkView chunk = FindHeapChunkByAddress(addr);
541  if (!chunk.IsValid()) {
542    Printf("AddressSanitizer can not describe address in more detail "
543           "(wild memory access suspected).\n");
544    return;
545  }
546  DescribeAccessToHeapChunk(chunk, addr, access_size);
547  CHECK(chunk.AllocTid() != kInvalidTid);
548  asanThreadRegistry().CheckLocked();
549  AsanThreadContext *alloc_thread =
550      GetThreadContextByTidLocked(chunk.AllocTid());
551  StackTrace alloc_stack = chunk.GetAllocStack();
552  char tname[128];
553  Decorator d;
554  AsanThreadContext *free_thread = nullptr;
555  if (chunk.FreeTid() != kInvalidTid) {
556    free_thread = GetThreadContextByTidLocked(chunk.FreeTid());
557    Printf("%sfreed by thread T%d%s here:%s\n", d.Allocation(),
558           free_thread->tid,
559           ThreadNameWithParenthesis(free_thread, tname, sizeof(tname)),
560           d.EndAllocation());
561    StackTrace free_stack = chunk.GetFreeStack();
562    free_stack.Print();
563    Printf("%spreviously allocated by thread T%d%s here:%s\n",
564           d.Allocation(), alloc_thread->tid,
565           ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)),
566           d.EndAllocation());
567  } else {
568    Printf("%sallocated by thread T%d%s here:%s\n", d.Allocation(),
569           alloc_thread->tid,
570           ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)),
571           d.EndAllocation());
572  }
573  alloc_stack.Print();
574  DescribeThread(GetCurrentThread());
575  if (free_thread)
576    DescribeThread(free_thread);
577  DescribeThread(alloc_thread);
578}
579
580static void DescribeAddress(uptr addr, uptr access_size, const char *bug_type) {
581  // Check if this is shadow or shadow gap.
582  if (DescribeAddressIfShadow(addr))
583    return;
584  CHECK(AddrIsInMem(addr));
585  if (DescribeAddressIfGlobal(addr, access_size, bug_type))
586    return;
587  if (DescribeAddressIfStack(addr, access_size))
588    return;
589  // Assume it is a heap address.
590  DescribeHeapAddress(addr, access_size);
591}
592
593// ------------------- Thread description -------------------- {{{1
594
595void DescribeThread(AsanThreadContext *context) {
596  CHECK(context);
597  asanThreadRegistry().CheckLocked();
598  // No need to announce the main thread.
599  if (context->tid == 0 || context->announced) {
600    return;
601  }
602  context->announced = true;
603  char tname[128];
604  InternalScopedString str(1024);
605  str.append("Thread T%d%s", context->tid,
606             ThreadNameWithParenthesis(context->tid, tname, sizeof(tname)));
607  if (context->parent_tid == kInvalidTid) {
608    str.append(" created by unknown thread\n");
609    Printf("%s", str.data());
610    return;
611  }
612  str.append(
613      " created by T%d%s here:\n", context->parent_tid,
614      ThreadNameWithParenthesis(context->parent_tid, tname, sizeof(tname)));
615  Printf("%s", str.data());
616  StackDepotGet(context->stack_id).Print();
617  // Recursively described parent thread if needed.
618  if (flags()->print_full_thread_history) {
619    AsanThreadContext *parent_context =
620        GetThreadContextByTidLocked(context->parent_tid);
621    DescribeThread(parent_context);
622  }
623}
624
625// -------------------- Different kinds of reports ----------------- {{{1
626
627// Use ScopedInErrorReport to run common actions just before and
628// immediately after printing error report.
629class ScopedInErrorReport {
630 public:
631  explicit ScopedInErrorReport(ReportData *report = nullptr,
632                               bool fatal = false) {
633    halt_on_error_ = fatal || flags()->halt_on_error;
634
635    if (lock_.TryLock()) {
636      StartReporting(report);
637      return;
638    }
639
640    // ASan found two bugs in different threads simultaneously.
641
642    u32 current_tid = GetCurrentTidOrInvalid();
643    if (reporting_thread_tid_ == current_tid ||
644        reporting_thread_tid_ == kInvalidTid) {
645      // This is either asynch signal or nested error during error reporting.
646      // Fail simple to avoid deadlocks in Report().
647
648      // Can't use Report() here because of potential deadlocks
649      // in nested signal handlers.
650      const char msg[] = "AddressSanitizer: nested bug in the same thread, "
651                         "aborting.\n";
652      WriteToFile(kStderrFd, msg, sizeof(msg));
653
654      internal__exit(common_flags()->exitcode);
655    }
656
657    if (halt_on_error_) {
658      // Do not print more than one report, otherwise they will mix up.
659      // Error reporting functions shouldn't return at this situation, as
660      // they are effectively no-returns.
661
662      Report("AddressSanitizer: while reporting a bug found another one. "
663             "Ignoring.\n");
664
665      // Sleep long enough to make sure that the thread which started
666      // to print an error report will finish doing it.
667      SleepForSeconds(Max(100, flags()->sleep_before_dying + 1));
668
669      // If we're still not dead for some reason, use raw _exit() instead of
670      // Die() to bypass any additional checks.
671      internal__exit(common_flags()->exitcode);
672    } else {
673      // The other thread will eventually finish reporting
674      // so it's safe to wait
675      lock_.Lock();
676    }
677
678    StartReporting(report);
679  }
680
681  ~ScopedInErrorReport() {
682    // Make sure the current thread is announced.
683    DescribeThread(GetCurrentThread());
684    // We may want to grab this lock again when printing stats.
685    asanThreadRegistry().Unlock();
686    // Print memory stats.
687    if (flags()->print_stats)
688      __asan_print_accumulated_stats();
689
690    // Copy the message buffer so that we could start logging without holding a
691    // lock that gets aquired during printing.
692    InternalScopedBuffer<char> buffer_copy(kErrorMessageBufferSize);
693    {
694      BlockingMutexLock l(&error_message_buf_mutex);
695      internal_memcpy(buffer_copy.data(),
696                      error_message_buffer, kErrorMessageBufferSize);
697    }
698
699    // Remove color sequences since logs cannot print them.
700    RemoveANSIEscapeSequencesFromString(buffer_copy.data());
701
702    LogFullErrorReport(buffer_copy.data());
703
704    if (error_report_callback) {
705      error_report_callback(buffer_copy.data());
706    }
707    CommonSanitizerReportMutex.Unlock();
708    reporting_thread_tid_ = kInvalidTid;
709    lock_.Unlock();
710    if (halt_on_error_) {
711      Report("ABORTING\n");
712      Die();
713    }
714  }
715
716 private:
717  void StartReporting(ReportData *report) {
718    if (report) report_data = *report;
719    report_happened = true;
720    ASAN_ON_ERROR();
721    // Make sure the registry and sanitizer report mutexes are locked while
722    // we're printing an error report.
723    // We can lock them only here to avoid self-deadlock in case of
724    // recursive reports.
725    asanThreadRegistry().Lock();
726    CommonSanitizerReportMutex.Lock();
727    reporting_thread_tid_ = GetCurrentTidOrInvalid();
728    Printf("===================================================="
729           "=============\n");
730  }
731
732  static StaticSpinMutex lock_;
733  static u32 reporting_thread_tid_;
734  bool halt_on_error_;
735};
736
737StaticSpinMutex ScopedInErrorReport::lock_;
738u32 ScopedInErrorReport::reporting_thread_tid_;
739
740void ReportStackOverflow(const SignalContext &sig) {
741  ScopedInErrorReport in_report;
742  Decorator d;
743  Printf("%s", d.Warning());
744  Report(
745      "ERROR: AddressSanitizer: stack-overflow on address %p"
746      " (pc %p bp %p sp %p T%d)\n",
747      (void *)sig.addr, (void *)sig.pc, (void *)sig.bp, (void *)sig.sp,
748      GetCurrentTidOrInvalid());
749  Printf("%s", d.EndWarning());
750  GET_STACK_TRACE_SIGNAL(sig);
751  stack.Print();
752  ReportErrorSummary("stack-overflow", &stack);
753}
754
755void ReportDeadlySignal(const char *description, const SignalContext &sig) {
756  ScopedInErrorReport in_report(/*report*/nullptr, /*fatal*/true);
757  Decorator d;
758  Printf("%s", d.Warning());
759  Report(
760      "ERROR: AddressSanitizer: %s on unknown address %p"
761      " (pc %p bp %p sp %p T%d)\n",
762      description, (void *)sig.addr, (void *)sig.pc, (void *)sig.bp,
763      (void *)sig.sp, GetCurrentTidOrInvalid());
764  if (sig.pc < GetPageSizeCached()) {
765    Report("Hint: pc points to the zero page.\n");
766  }
767  Printf("%s", d.EndWarning());
768  GET_STACK_TRACE_SIGNAL(sig);
769  stack.Print();
770  MaybeDumpInstructionBytes(sig.pc);
771  Printf("AddressSanitizer can not provide additional info.\n");
772  ReportErrorSummary(description, &stack);
773}
774
775void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack) {
776  ScopedInErrorReport in_report;
777  Decorator d;
778  Printf("%s", d.Warning());
779  char tname[128];
780  u32 curr_tid = GetCurrentTidOrInvalid();
781  Report("ERROR: AddressSanitizer: attempting double-free on %p in "
782         "thread T%d%s:\n",
783         addr, curr_tid,
784         ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)));
785  Printf("%s", d.EndWarning());
786  CHECK_GT(free_stack->size, 0);
787  GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
788  stack.Print();
789  DescribeHeapAddress(addr, 1);
790  ReportErrorSummary("double-free", &stack);
791}
792
793void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
794                                 BufferedStackTrace *free_stack) {
795  ScopedInErrorReport in_report;
796  Decorator d;
797  Printf("%s", d.Warning());
798  char tname[128];
799  u32 curr_tid = GetCurrentTidOrInvalid();
800  Report("ERROR: AddressSanitizer: new-delete-type-mismatch on %p in "
801         "thread T%d%s:\n",
802         addr, curr_tid,
803         ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)));
804  Printf("%s  object passed to delete has wrong type:\n", d.EndWarning());
805  Printf("  size of the allocated type:   %zd bytes;\n"
806         "  size of the deallocated type: %zd bytes.\n",
807         asan_mz_size(reinterpret_cast<void*>(addr)), delete_size);
808  CHECK_GT(free_stack->size, 0);
809  GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
810  stack.Print();
811  DescribeHeapAddress(addr, 1);
812  ReportErrorSummary("new-delete-type-mismatch", &stack);
813  Report("HINT: if you don't care about these errors you may set "
814         "ASAN_OPTIONS=new_delete_type_mismatch=0\n");
815}
816
817void ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack) {
818  ScopedInErrorReport in_report;
819  Decorator d;
820  Printf("%s", d.Warning());
821  char tname[128];
822  u32 curr_tid = GetCurrentTidOrInvalid();
823  Report("ERROR: AddressSanitizer: attempting free on address "
824             "which was not malloc()-ed: %p in thread T%d%s\n", addr,
825         curr_tid, ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)));
826  Printf("%s", d.EndWarning());
827  CHECK_GT(free_stack->size, 0);
828  GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
829  stack.Print();
830  DescribeHeapAddress(addr, 1);
831  ReportErrorSummary("bad-free", &stack);
832}
833
834void ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack,
835                             AllocType alloc_type,
836                             AllocType dealloc_type) {
837  static const char *alloc_names[] =
838    {"INVALID", "malloc", "operator new", "operator new []"};
839  static const char *dealloc_names[] =
840    {"INVALID", "free", "operator delete", "operator delete []"};
841  CHECK_NE(alloc_type, dealloc_type);
842  ScopedInErrorReport in_report;
843  Decorator d;
844  Printf("%s", d.Warning());
845  Report("ERROR: AddressSanitizer: alloc-dealloc-mismatch (%s vs %s) on %p\n",
846        alloc_names[alloc_type], dealloc_names[dealloc_type], addr);
847  Printf("%s", d.EndWarning());
848  CHECK_GT(free_stack->size, 0);
849  GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
850  stack.Print();
851  DescribeHeapAddress(addr, 1);
852  ReportErrorSummary("alloc-dealloc-mismatch", &stack);
853  Report("HINT: if you don't care about these errors you may set "
854         "ASAN_OPTIONS=alloc_dealloc_mismatch=0\n");
855}
856
857void ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack) {
858  ScopedInErrorReport in_report;
859  Decorator d;
860  Printf("%s", d.Warning());
861  Report("ERROR: AddressSanitizer: attempting to call "
862             "malloc_usable_size() for pointer which is "
863             "not owned: %p\n", addr);
864  Printf("%s", d.EndWarning());
865  stack->Print();
866  DescribeHeapAddress(addr, 1);
867  ReportErrorSummary("bad-malloc_usable_size", stack);
868}
869
870void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr,
871                                             BufferedStackTrace *stack) {
872  ScopedInErrorReport in_report;
873  Decorator d;
874  Printf("%s", d.Warning());
875  Report("ERROR: AddressSanitizer: attempting to call "
876             "__sanitizer_get_allocated_size() for pointer which is "
877             "not owned: %p\n", addr);
878  Printf("%s", d.EndWarning());
879  stack->Print();
880  DescribeHeapAddress(addr, 1);
881  ReportErrorSummary("bad-__sanitizer_get_allocated_size", stack);
882}
883
884void ReportStringFunctionMemoryRangesOverlap(const char *function,
885                                             const char *offset1, uptr length1,
886                                             const char *offset2, uptr length2,
887                                             BufferedStackTrace *stack) {
888  ScopedInErrorReport in_report;
889  Decorator d;
890  char bug_type[100];
891  internal_snprintf(bug_type, sizeof(bug_type), "%s-param-overlap", function);
892  Printf("%s", d.Warning());
893  Report("ERROR: AddressSanitizer: %s: "
894             "memory ranges [%p,%p) and [%p, %p) overlap\n", \
895             bug_type, offset1, offset1 + length1, offset2, offset2 + length2);
896  Printf("%s", d.EndWarning());
897  stack->Print();
898  DescribeAddress((uptr)offset1, length1, bug_type);
899  DescribeAddress((uptr)offset2, length2, bug_type);
900  ReportErrorSummary(bug_type, stack);
901}
902
903void ReportStringFunctionSizeOverflow(uptr offset, uptr size,
904                                      BufferedStackTrace *stack) {
905  ScopedInErrorReport in_report;
906  Decorator d;
907  const char *bug_type = "negative-size-param";
908  Printf("%s", d.Warning());
909  Report("ERROR: AddressSanitizer: %s: (size=%zd)\n", bug_type, size);
910  Printf("%s", d.EndWarning());
911  stack->Print();
912  DescribeAddress(offset, size, bug_type);
913  ReportErrorSummary(bug_type, stack);
914}
915
916void ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end,
917                                                  uptr old_mid, uptr new_mid,
918                                                  BufferedStackTrace *stack) {
919  ScopedInErrorReport in_report;
920  Report("ERROR: AddressSanitizer: bad parameters to "
921         "__sanitizer_annotate_contiguous_container:\n"
922         "      beg     : %p\n"
923         "      end     : %p\n"
924         "      old_mid : %p\n"
925         "      new_mid : %p\n",
926         beg, end, old_mid, new_mid);
927  uptr granularity = SHADOW_GRANULARITY;
928  if (!IsAligned(beg, granularity))
929    Report("ERROR: beg is not aligned by %d\n", granularity);
930  stack->Print();
931  ReportErrorSummary("bad-__sanitizer_annotate_contiguous_container", stack);
932}
933
934void ReportODRViolation(const __asan_global *g1, u32 stack_id1,
935                        const __asan_global *g2, u32 stack_id2) {
936  ScopedInErrorReport in_report;
937  Decorator d;
938  Printf("%s", d.Warning());
939  Report("ERROR: AddressSanitizer: odr-violation (%p):\n", g1->beg);
940  Printf("%s", d.EndWarning());
941  InternalScopedString g1_loc(256), g2_loc(256);
942  PrintGlobalLocation(&g1_loc, *g1);
943  PrintGlobalLocation(&g2_loc, *g2);
944  Printf("  [1] size=%zd '%s' %s\n", g1->size,
945         MaybeDemangleGlobalName(g1->name), g1_loc.data());
946  Printf("  [2] size=%zd '%s' %s\n", g2->size,
947         MaybeDemangleGlobalName(g2->name), g2_loc.data());
948  if (stack_id1 && stack_id2) {
949    Printf("These globals were registered at these points:\n");
950    Printf("  [1]:\n");
951    StackDepotGet(stack_id1).Print();
952    Printf("  [2]:\n");
953    StackDepotGet(stack_id2).Print();
954  }
955  Report("HINT: if you don't care about these errors you may set "
956         "ASAN_OPTIONS=detect_odr_violation=0\n");
957  InternalScopedString error_msg(256);
958  error_msg.append("odr-violation: global '%s' at %s",
959                   MaybeDemangleGlobalName(g1->name), g1_loc.data());
960  ReportErrorSummary(error_msg.data());
961}
962
963// ----------------------- CheckForInvalidPointerPair ----------- {{{1
964static NOINLINE void
965ReportInvalidPointerPair(uptr pc, uptr bp, uptr sp, uptr a1, uptr a2) {
966  ScopedInErrorReport in_report;
967  const char *bug_type = "invalid-pointer-pair";
968  Decorator d;
969  Printf("%s", d.Warning());
970  Report("ERROR: AddressSanitizer: invalid-pointer-pair: %p %p\n", a1, a2);
971  Printf("%s", d.EndWarning());
972  GET_STACK_TRACE_FATAL(pc, bp);
973  stack.Print();
974  DescribeAddress(a1, 1, bug_type);
975  DescribeAddress(a2, 1, bug_type);
976  ReportErrorSummary(bug_type, &stack);
977}
978
979static INLINE void CheckForInvalidPointerPair(void *p1, void *p2) {
980  if (!flags()->detect_invalid_pointer_pairs) return;
981  uptr a1 = reinterpret_cast<uptr>(p1);
982  uptr a2 = reinterpret_cast<uptr>(p2);
983  AsanChunkView chunk1 = FindHeapChunkByAddress(a1);
984  AsanChunkView chunk2 = FindHeapChunkByAddress(a2);
985  bool valid1 = chunk1.IsValid();
986  bool valid2 = chunk2.IsValid();
987  if ((valid1 != valid2) || (valid1 && valid2 && !chunk1.Eq(chunk2))) {
988    GET_CALLER_PC_BP_SP;                                              \
989    return ReportInvalidPointerPair(pc, bp, sp, a1, a2);
990  }
991}
992// ----------------------- Mac-specific reports ----------------- {{{1
993
994void ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name,
995                               BufferedStackTrace *stack) {
996  ScopedInErrorReport in_report;
997  Printf("mz_realloc(%p) -- attempting to realloc unallocated memory.\n"
998             "This is an unrecoverable problem, exiting now.\n",
999             addr);
1000  PrintZoneForPointer(addr, zone_ptr, zone_name);
1001  stack->Print();
1002  DescribeHeapAddress(addr, 1);
1003}
1004
1005// -------------- SuppressErrorReport -------------- {{{1
1006// Avoid error reports duplicating for ASan recover mode.
1007static bool SuppressErrorReport(uptr pc) {
1008  if (!common_flags()->suppress_equal_pcs) return false;
1009  for (unsigned i = 0; i < kAsanBuggyPcPoolSize; i++) {
1010    uptr cmp = atomic_load_relaxed(&AsanBuggyPcPool[i]);
1011    if (cmp == 0 && atomic_compare_exchange_strong(&AsanBuggyPcPool[i], &cmp,
1012                                                   pc, memory_order_relaxed))
1013      return false;
1014    if (cmp == pc) return true;
1015  }
1016  Die();
1017}
1018
1019void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write,
1020                        uptr access_size, u32 exp, bool fatal) {
1021  if (!fatal && SuppressErrorReport(pc)) return;
1022  ENABLE_FRAME_POINTER;
1023
1024  // Optimization experiments.
1025  // The experiments can be used to evaluate potential optimizations that remove
1026  // instrumentation (assess false negatives). Instead of completely removing
1027  // some instrumentation, compiler can emit special calls into runtime
1028  // (e.g. __asan_report_exp_load1 instead of __asan_report_load1) and pass
1029  // mask of experiments (exp).
1030  // The reaction to a non-zero value of exp is to be defined.
1031  (void)exp;
1032
1033  // Determine the error type.
1034  const char *bug_descr = "unknown-crash";
1035  if (AddrIsInMem(addr)) {
1036    u8 *shadow_addr = (u8*)MemToShadow(addr);
1037    // If we are accessing 16 bytes, look at the second shadow byte.
1038    if (*shadow_addr == 0 && access_size > SHADOW_GRANULARITY)
1039      shadow_addr++;
1040    // If we are in the partial right redzone, look at the next shadow byte.
1041    if (*shadow_addr > 0 && *shadow_addr < 128)
1042      shadow_addr++;
1043    switch (*shadow_addr) {
1044      case kAsanHeapLeftRedzoneMagic:
1045      case kAsanHeapRightRedzoneMagic:
1046      case kAsanArrayCookieMagic:
1047        bug_descr = "heap-buffer-overflow";
1048        break;
1049      case kAsanHeapFreeMagic:
1050        bug_descr = "heap-use-after-free";
1051        break;
1052      case kAsanStackLeftRedzoneMagic:
1053        bug_descr = "stack-buffer-underflow";
1054        break;
1055      case kAsanInitializationOrderMagic:
1056        bug_descr = "initialization-order-fiasco";
1057        break;
1058      case kAsanStackMidRedzoneMagic:
1059      case kAsanStackRightRedzoneMagic:
1060      case kAsanStackPartialRedzoneMagic:
1061        bug_descr = "stack-buffer-overflow";
1062        break;
1063      case kAsanStackAfterReturnMagic:
1064        bug_descr = "stack-use-after-return";
1065        break;
1066      case kAsanUserPoisonedMemoryMagic:
1067        bug_descr = "use-after-poison";
1068        break;
1069      case kAsanContiguousContainerOOBMagic:
1070        bug_descr = "container-overflow";
1071        break;
1072      case kAsanStackUseAfterScopeMagic:
1073        bug_descr = "stack-use-after-scope";
1074        break;
1075      case kAsanGlobalRedzoneMagic:
1076        bug_descr = "global-buffer-overflow";
1077        break;
1078      case kAsanIntraObjectRedzone:
1079        bug_descr = "intra-object-overflow";
1080        break;
1081      case kAsanAllocaLeftMagic:
1082      case kAsanAllocaRightMagic:
1083        bug_descr = "dynamic-stack-buffer-overflow";
1084        break;
1085    }
1086  }
1087
1088  ReportData report = { pc, sp, bp, addr, (bool)is_write, access_size,
1089                        bug_descr };
1090  ScopedInErrorReport in_report(&report, fatal);
1091
1092  Decorator d;
1093  Printf("%s", d.Warning());
1094  Report("ERROR: AddressSanitizer: %s on address "
1095             "%p at pc %p bp %p sp %p\n",
1096             bug_descr, (void*)addr, pc, bp, sp);
1097  Printf("%s", d.EndWarning());
1098
1099  u32 curr_tid = GetCurrentTidOrInvalid();
1100  char tname[128];
1101  Printf("%s%s of size %zu at %p thread T%d%s%s\n",
1102         d.Access(),
1103         access_size ? (is_write ? "WRITE" : "READ") : "ACCESS",
1104         access_size, (void*)addr, curr_tid,
1105         ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)),
1106         d.EndAccess());
1107
1108  GET_STACK_TRACE_FATAL(pc, bp);
1109  stack.Print();
1110
1111  DescribeAddress(addr, access_size, bug_descr);
1112  ReportErrorSummary(bug_descr, &stack);
1113  PrintShadowMemoryForAddress(addr);
1114}
1115
1116}  // namespace __asan
1117
1118// --------------------------- Interface --------------------- {{{1
1119using namespace __asan;  // NOLINT
1120
1121void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write,
1122                         uptr access_size, u32 exp) {
1123  ENABLE_FRAME_POINTER;
1124  bool fatal = flags()->halt_on_error;
1125  ReportGenericError(pc, bp, sp, addr, is_write, access_size, exp, fatal);
1126}
1127
1128void NOINLINE __asan_set_error_report_callback(void (*callback)(const char*)) {
1129  BlockingMutexLock l(&error_message_buf_mutex);
1130  error_report_callback = callback;
1131}
1132
1133void __asan_describe_address(uptr addr) {
1134  // Thread registry must be locked while we're describing an address.
1135  asanThreadRegistry().Lock();
1136  DescribeAddress(addr, 1, "");
1137  asanThreadRegistry().Unlock();
1138}
1139
1140int __asan_report_present() {
1141  return report_happened ? 1 : 0;
1142}
1143
1144uptr __asan_get_report_pc() {
1145  return report_data.pc;
1146}
1147
1148uptr __asan_get_report_bp() {
1149  return report_data.bp;
1150}
1151
1152uptr __asan_get_report_sp() {
1153  return report_data.sp;
1154}
1155
1156uptr __asan_get_report_address() {
1157  return report_data.addr;
1158}
1159
1160int __asan_get_report_access_type() {
1161  return report_data.is_write ? 1 : 0;
1162}
1163
1164uptr __asan_get_report_access_size() {
1165  return report_data.access_size;
1166}
1167
1168const char *__asan_get_report_description() {
1169  return report_data.description;
1170}
1171
1172extern "C" {
1173SANITIZER_INTERFACE_ATTRIBUTE
1174void __sanitizer_ptr_sub(void *a, void *b) {
1175  CheckForInvalidPointerPair(a, b);
1176}
1177SANITIZER_INTERFACE_ATTRIBUTE
1178void __sanitizer_ptr_cmp(void *a, void *b) {
1179  CheckForInvalidPointerPair(a, b);
1180}
1181} // extern "C"
1182
1183#if !SANITIZER_SUPPORTS_WEAK_HOOKS
1184// Provide default implementation of __asan_on_error that does nothing
1185// and may be overriden by user.
1186SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE
1187void __asan_on_error() {}
1188#endif
1189