1 //===-- asan_report.cc ----------------------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // This file is a part of AddressSanitizer, an address sanity checker.
10 // This file contains error reporting code.
11 //===----------------------------------------------------------------------===//
12 #include "asan_flags.h"
13 #include "asan_internal.h"
14 #include "asan_mapping.h"
15 #include "asan_report.h"
16 #include "asan_stack.h"
17 #include "asan_thread.h"
18 #include "asan_thread_registry.h"
19 #include "sanitizer_common/sanitizer_common.h"
20 #include "sanitizer_common/sanitizer_report_decorator.h"
21 #include "sanitizer_common/sanitizer_symbolizer.h"
25 // -------------------- User-specified callbacks ----------------- {{{1
26 static void (*error_report_callback
)(const char*);
27 static char *error_message_buffer
= 0;
28 static uptr error_message_buffer_pos
= 0;
29 static uptr error_message_buffer_size
= 0;
31 void AppendToErrorMessageBuffer(const char *buffer
) {
32 if (error_message_buffer
) {
33 uptr length
= internal_strlen(buffer
);
34 CHECK_GE(error_message_buffer_size
, error_message_buffer_pos
);
35 uptr remaining
= error_message_buffer_size
- error_message_buffer_pos
;
36 internal_strncpy(error_message_buffer
+ error_message_buffer_pos
,
38 error_message_buffer
[error_message_buffer_size
- 1] = '\0';
39 // FIXME: reallocate the buffer instead of truncating the message.
40 error_message_buffer_pos
+= remaining
> length
? length
: remaining
;
44 // ---------------------- Decorator ------------------------------ {{{1
45 bool PrintsToTtyCached() {
46 static int cached
= 0;
47 static bool prints_to_tty
;
48 if (!cached
) { // Ok wrt threads since we are printing only from one thread.
49 prints_to_tty
= PrintsToTty();
54 class Decorator
: private __sanitizer::AnsiColorDecorator
{
56 Decorator() : __sanitizer::AnsiColorDecorator(PrintsToTtyCached()) { }
57 const char *Warning() { return Red(); }
58 const char *EndWarning() { return Default(); }
59 const char *Access() { return Blue(); }
60 const char *EndAccess() { return Default(); }
61 const char *Location() { return Green(); }
62 const char *EndLocation() { return Default(); }
63 const char *Allocation() { return Magenta(); }
64 const char *EndAllocation() { return Default(); }
66 const char *ShadowByte(u8 byte
) {
68 case kAsanHeapLeftRedzoneMagic
:
69 case kAsanHeapRightRedzoneMagic
:
71 case kAsanHeapFreeMagic
:
73 case kAsanStackLeftRedzoneMagic
:
74 case kAsanStackMidRedzoneMagic
:
75 case kAsanStackRightRedzoneMagic
:
76 case kAsanStackPartialRedzoneMagic
:
78 case kAsanStackAfterReturnMagic
:
80 case kAsanInitializationOrderMagic
:
82 case kAsanUserPoisonedMemoryMagic
:
84 case kAsanStackUseAfterScopeMagic
:
86 case kAsanGlobalRedzoneMagic
:
88 case kAsanInternalHeapMagic
:
94 const char *EndShadowByte() { return Default(); }
97 // ---------------------- Helper functions ----------------------- {{{1
99 static void PrintShadowByte(const char *before
, u8 byte
,
100 const char *after
= "\n") {
102 Printf("%s%s%x%x%s%s", before
,
103 d
.ShadowByte(byte
), byte
>> 4, byte
& 15, d
.EndShadowByte(), after
);
106 static void PrintShadowBytes(const char *before
, u8
*bytes
,
107 u8
*guilty
, uptr n
) {
110 Printf("%s%p:", before
, bytes
);
111 for (uptr i
= 0; i
< n
; i
++) {
113 const char *before
= p
== guilty
? "[" :
114 p
- 1 == guilty
? "" : " ";
115 const char *after
= p
== guilty
? "]" : "";
116 PrintShadowByte(before
, *p
, after
);
121 static void PrintLegend() {
122 Printf("Shadow byte legend (one shadow byte represents %d "
123 "application bytes):\n", (int)SHADOW_GRANULARITY
);
124 PrintShadowByte(" Addressable: ", 0);
125 Printf(" Partially addressable: ");
126 for (uptr i
= 1; i
< SHADOW_GRANULARITY
; i
++)
127 PrintShadowByte("", i
, " ");
129 PrintShadowByte(" Heap left redzone: ", kAsanHeapLeftRedzoneMagic
);
130 PrintShadowByte(" Heap righ redzone: ", kAsanHeapRightRedzoneMagic
);
131 PrintShadowByte(" Freed Heap region: ", kAsanHeapFreeMagic
);
132 PrintShadowByte(" Stack left redzone: ", kAsanStackLeftRedzoneMagic
);
133 PrintShadowByte(" Stack mid redzone: ", kAsanStackMidRedzoneMagic
);
134 PrintShadowByte(" Stack right redzone: ", kAsanStackRightRedzoneMagic
);
135 PrintShadowByte(" Stack partial redzone: ", kAsanStackPartialRedzoneMagic
);
136 PrintShadowByte(" Stack after return: ", kAsanStackAfterReturnMagic
);
137 PrintShadowByte(" Stack use after scope: ", kAsanStackUseAfterScopeMagic
);
138 PrintShadowByte(" Global redzone: ", kAsanGlobalRedzoneMagic
);
139 PrintShadowByte(" Global init order: ", kAsanInitializationOrderMagic
);
140 PrintShadowByte(" Poisoned by user: ", kAsanUserPoisonedMemoryMagic
);
141 PrintShadowByte(" ASan internal: ", kAsanInternalHeapMagic
);
144 static void PrintShadowMemoryForAddress(uptr addr
) {
145 if (!AddrIsInMem(addr
))
147 uptr shadow_addr
= MemToShadow(addr
);
148 const uptr n_bytes_per_row
= 16;
149 uptr aligned_shadow
= shadow_addr
& ~(n_bytes_per_row
- 1);
150 Printf("Shadow bytes around the buggy address:\n");
151 for (int i
= -5; i
<= 5; i
++) {
152 const char *prefix
= (i
== 0) ? "=>" : " ";
153 PrintShadowBytes(prefix
,
154 (u8
*)(aligned_shadow
+ i
* n_bytes_per_row
),
155 (u8
*)shadow_addr
, n_bytes_per_row
);
157 if (flags()->print_legend
)
161 static void PrintZoneForPointer(uptr ptr
, uptr zone_ptr
,
162 const char *zone_name
) {
165 Printf("malloc_zone_from_ptr(%p) = %p, which is %s\n",
166 ptr
, zone_ptr
, zone_name
);
168 Printf("malloc_zone_from_ptr(%p) = %p, which doesn't have a name\n",
172 Printf("malloc_zone_from_ptr(%p) = 0\n", ptr
);
176 // ---------------------- Address Descriptions ------------------- {{{1
178 static bool IsASCII(unsigned char c
) {
179 return /*0x00 <= c &&*/ c
<= 0x7F;
182 // Check if the global is a zero-terminated ASCII string. If so, print it.
183 static void PrintGlobalNameIfASCII(const __asan_global
&g
) {
184 for (uptr p
= g
.beg
; p
< g
.beg
+ g
.size
- 1; p
++) {
185 if (!IsASCII(*(unsigned char*)p
)) return;
187 if (*(char*)(g
.beg
+ g
.size
- 1) != 0) return;
188 Printf(" '%s' is ascii string '%s'\n", g
.name
, (char*)g
.beg
);
191 bool DescribeAddressRelativeToGlobal(uptr addr
, uptr size
,
192 const __asan_global
&g
) {
193 static const uptr kMinimalDistanceFromAnotherGlobal
= 64;
194 if (addr
<= g
.beg
- kMinimalDistanceFromAnotherGlobal
) return false;
195 if (addr
>= g
.beg
+ g
.size_with_redzone
) return false;
197 Printf("%s", d
.Location());
199 Printf("%p is located %zd bytes to the left", (void*)addr
, g
.beg
- addr
);
200 } else if (addr
+ size
> g
.beg
+ g
.size
) {
201 if (addr
< g
.beg
+ g
.size
)
202 addr
= g
.beg
+ g
.size
;
203 Printf("%p is located %zd bytes to the right", (void*)addr
,
204 addr
- (g
.beg
+ g
.size
));
207 Printf("%p is located %zd bytes inside", (void*)addr
, addr
- g
.beg
);
209 Printf(" of global variable '%s' (0x%zx) of size %zu\n",
210 g
.name
, g
.beg
, g
.size
);
211 Printf("%s", d
.EndLocation());
212 PrintGlobalNameIfASCII(g
);
216 bool DescribeAddressIfShadow(uptr addr
) {
217 if (AddrIsInMem(addr
))
219 static const char kAddrInShadowReport
[] =
220 "Address %p is located in the %s.\n";
221 if (AddrIsInShadowGap(addr
)) {
222 Printf(kAddrInShadowReport
, addr
, "shadow gap area");
225 if (AddrIsInHighShadow(addr
)) {
226 Printf(kAddrInShadowReport
, addr
, "high shadow area");
229 if (AddrIsInLowShadow(addr
)) {
230 Printf(kAddrInShadowReport
, addr
, "low shadow area");
233 CHECK(0 && "Address is not in memory and not in shadow?");
237 bool DescribeAddressIfStack(uptr addr
, uptr access_size
) {
238 AsanThread
*t
= asanThreadRegistry().FindThreadByStackAddress(addr
);
239 if (!t
) return false;
240 const sptr kBufSize
= 4095;
243 const char *frame_descr
= t
->GetFrameNameByAddr(addr
, &offset
);
244 // This string is created by the compiler and has the following form:
245 // "FunctioName n alloc_1 alloc_2 ... alloc_n"
246 // where alloc_i looks like "offset size len ObjectName ".
248 // Report the function name and the offset.
249 const char *name_end
= internal_strchr(frame_descr
, ' ');
252 internal_strncat(buf
, frame_descr
,
254 static_cast<sptr
>(name_end
- frame_descr
)));
256 Printf("%s", d
.Location());
257 Printf("Address %p is located at offset %zu "
258 "in frame <%s> of T%d's stack:\n",
259 (void*)addr
, offset
, Demangle(buf
), t
->tid());
260 Printf("%s", d
.EndLocation());
261 // Report the number of stack objects.
263 uptr n_objects
= internal_simple_strtoll(name_end
, &p
, 10);
264 CHECK(n_objects
> 0);
265 Printf(" This frame has %zu object(s):\n", n_objects
);
266 // Report all objects in this frame.
267 for (uptr i
= 0; i
< n_objects
; i
++) {
270 beg
= internal_simple_strtoll(p
, &p
, 10);
271 size
= internal_simple_strtoll(p
, &p
, 10);
272 len
= internal_simple_strtoll(p
, &p
, 10);
273 if (beg
<= 0 || size
<= 0 || len
< 0 || *p
!= ' ') {
274 Printf("AddressSanitizer can't parse the stack frame "
275 "descriptor: |%s|\n", frame_descr
);
280 internal_strncat(buf
, p
, Min(kBufSize
, len
));
282 Printf(" [%zu, %zu) '%s'\n", beg
, beg
+ size
, buf
);
284 Printf("HINT: this may be a false positive if your program uses "
285 "some custom stack unwind mechanism or swapcontext\n"
286 " (longjmp and C++ exceptions *are* supported)\n");
287 DescribeThread(t
->summary());
291 static void DescribeAccessToHeapChunk(AsanChunkView chunk
, uptr addr
,
295 Printf("%s", d
.Location());
296 if (chunk
.AddrIsAtLeft(addr
, access_size
, &offset
)) {
297 Printf("%p is located %zd bytes to the left of", (void*)addr
, offset
);
298 } else if (chunk
.AddrIsAtRight(addr
, access_size
, &offset
)) {
303 Printf("%p is located %zd bytes to the right of", (void*)addr
, offset
);
304 } else if (chunk
.AddrIsInside(addr
, access_size
, &offset
)) {
305 Printf("%p is located %zd bytes inside of", (void*)addr
, offset
);
307 Printf("%p is located somewhere around (this is AddressSanitizer bug!)",
310 Printf(" %zu-byte region [%p,%p)\n", chunk
.UsedSize(),
311 (void*)(chunk
.Beg()), (void*)(chunk
.End()));
312 Printf("%s", d
.EndLocation());
315 // Return " (thread_name) " or an empty string if the name is empty.
316 const char *ThreadNameWithParenthesis(AsanThreadSummary
*t
, char buff
[],
318 const char *name
= t
->name();
319 if (*name
== 0) return "";
321 internal_strncat(buff
, " (", 3);
322 internal_strncat(buff
, name
, buff_len
- 4);
323 internal_strncat(buff
, ")", 2);
327 const char *ThreadNameWithParenthesis(u32 tid
, char buff
[],
329 if (tid
== kInvalidTid
) return "";
330 AsanThreadSummary
*t
= asanThreadRegistry().FindByTid(tid
);
331 return ThreadNameWithParenthesis(t
, buff
, buff_len
);
334 void DescribeHeapAddress(uptr addr
, uptr access_size
) {
335 AsanChunkView chunk
= FindHeapChunkByAddress(addr
);
336 if (!chunk
.IsValid()) return;
337 DescribeAccessToHeapChunk(chunk
, addr
, access_size
);
338 CHECK(chunk
.AllocTid() != kInvalidTid
);
339 AsanThreadSummary
*alloc_thread
=
340 asanThreadRegistry().FindByTid(chunk
.AllocTid());
341 StackTrace alloc_stack
;
342 chunk
.GetAllocStack(&alloc_stack
);
343 AsanThread
*t
= asanThreadRegistry().GetCurrent();
347 if (chunk
.FreeTid() != kInvalidTid
) {
348 AsanThreadSummary
*free_thread
=
349 asanThreadRegistry().FindByTid(chunk
.FreeTid());
350 Printf("%sfreed by thread T%d%s here:%s\n", d
.Allocation(),
352 ThreadNameWithParenthesis(free_thread
, tname
, sizeof(tname
)),
354 StackTrace free_stack
;
355 chunk
.GetFreeStack(&free_stack
);
356 PrintStack(&free_stack
);
357 Printf("%spreviously allocated by thread T%d%s here:%s\n",
358 d
.Allocation(), alloc_thread
->tid(),
359 ThreadNameWithParenthesis(alloc_thread
, tname
, sizeof(tname
)),
361 PrintStack(&alloc_stack
);
362 DescribeThread(t
->summary());
363 DescribeThread(free_thread
);
364 DescribeThread(alloc_thread
);
366 Printf("%sallocated by thread T%d%s here:%s\n", d
.Allocation(),
368 ThreadNameWithParenthesis(alloc_thread
, tname
, sizeof(tname
)),
370 PrintStack(&alloc_stack
);
371 DescribeThread(t
->summary());
372 DescribeThread(alloc_thread
);
376 void DescribeAddress(uptr addr
, uptr access_size
) {
377 // Check if this is shadow or shadow gap.
378 if (DescribeAddressIfShadow(addr
))
380 CHECK(AddrIsInMem(addr
));
381 if (DescribeAddressIfGlobal(addr
, access_size
))
383 if (DescribeAddressIfStack(addr
, access_size
))
385 // Assume it is a heap address.
386 DescribeHeapAddress(addr
, access_size
);
389 // ------------------- Thread description -------------------- {{{1
391 void DescribeThread(AsanThreadSummary
*summary
) {
393 // No need to announce the main thread.
394 if (summary
->tid() == 0 || summary
->announced()) {
397 summary
->set_announced(true);
399 Printf("Thread T%d%s", summary
->tid(),
400 ThreadNameWithParenthesis(summary
->tid(), tname
, sizeof(tname
)));
401 Printf(" created by T%d%s here:\n",
402 summary
->parent_tid(),
403 ThreadNameWithParenthesis(summary
->parent_tid(),
404 tname
, sizeof(tname
)));
405 PrintStack(summary
->stack());
406 // Recursively described parent thread if needed.
407 if (flags()->print_full_thread_history
) {
408 AsanThreadSummary
*parent_summary
=
409 asanThreadRegistry().FindByTid(summary
->parent_tid());
410 DescribeThread(parent_summary
);
414 // -------------------- Different kinds of reports ----------------- {{{1
416 // Use ScopedInErrorReport to run common actions just before and
417 // immediately after printing error report.
418 class ScopedInErrorReport
{
420 ScopedInErrorReport() {
421 static atomic_uint32_t num_calls
;
422 static u32 reporting_thread_tid
;
423 if (atomic_fetch_add(&num_calls
, 1, memory_order_relaxed
) != 0) {
424 // Do not print more than one report, otherwise they will mix up.
425 // Error reporting functions shouldn't return at this situation, as
426 // they are defined as no-return.
427 Report("AddressSanitizer: while reporting a bug found another one."
429 u32 current_tid
= asanThreadRegistry().GetCurrentTidOrInvalid();
430 if (current_tid
!= reporting_thread_tid
) {
431 // ASan found two bugs in different threads simultaneously. Sleep
432 // long enough to make sure that the thread which started to print
433 // an error report will finish doing it.
434 SleepForSeconds(Max(100, flags()->sleep_before_dying
+ 1));
436 // If we're still not dead for some reason, use raw _exit() instead of
437 // Die() to bypass any additional checks.
438 internal__exit(flags()->exitcode
);
441 reporting_thread_tid
= asanThreadRegistry().GetCurrentTidOrInvalid();
442 Printf("===================================================="
444 if (reporting_thread_tid
!= kInvalidTid
) {
445 // We started reporting an error message. Stop using the fake stack
446 // in case we call an instrumented function from a symbolizer.
447 AsanThread
*curr_thread
= asanThreadRegistry().GetCurrent();
449 curr_thread
->fake_stack().StopUsingFakeStack();
452 // Destructor is NORETURN, as functions that report errors are.
453 NORETURN
~ScopedInErrorReport() {
454 // Make sure the current thread is announced.
455 AsanThread
*curr_thread
= asanThreadRegistry().GetCurrent();
457 DescribeThread(curr_thread
->summary());
459 // Print memory stats.
460 if (flags()->print_stats
)
461 __asan_print_accumulated_stats();
462 if (error_report_callback
) {
463 error_report_callback(error_message_buffer
);
465 Report("ABORTING\n");
470 static void ReportSummary(const char *error_type
, StackTrace
*stack
) {
471 if (!stack
->size
) return;
472 if (IsSymbolizerAvailable()) {
474 // Currently, we include the first stack frame into the report summary.
475 // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc).
476 SymbolizeCode(stack
->trace
[0], &ai
, 1);
477 ReportErrorSummary(error_type
,
478 StripPathPrefix(ai
.file
, flags()->strip_path_prefix
),
479 ai
.line
, ai
.function
);
481 // FIXME: do we need to print anything at all if there is no symbolizer?
484 void ReportSIGSEGV(uptr pc
, uptr sp
, uptr bp
, uptr addr
) {
485 ScopedInErrorReport in_report
;
487 Printf("%s", d
.Warning());
488 Report("ERROR: AddressSanitizer: SEGV on unknown address %p"
489 " (pc %p sp %p bp %p T%d)\n",
490 (void*)addr
, (void*)pc
, (void*)sp
, (void*)bp
,
491 asanThreadRegistry().GetCurrentTidOrInvalid());
492 Printf("%s", d
.EndWarning());
493 Printf("AddressSanitizer can not provide additional info.\n");
494 GET_STACK_TRACE_FATAL(pc
, bp
);
496 ReportSummary("SEGV", &stack
);
499 void ReportDoubleFree(uptr addr
, StackTrace
*stack
) {
500 ScopedInErrorReport in_report
;
502 Printf("%s", d
.Warning());
503 Report("ERROR: AddressSanitizer: attempting double-free on %p:\n", addr
);
504 Printf("%s", d
.EndWarning());
506 DescribeHeapAddress(addr
, 1);
507 ReportSummary("double-free", stack
);
510 void ReportFreeNotMalloced(uptr addr
, StackTrace
*stack
) {
511 ScopedInErrorReport in_report
;
513 Printf("%s", d
.Warning());
514 Report("ERROR: AddressSanitizer: attempting free on address "
515 "which was not malloc()-ed: %p\n", addr
);
516 Printf("%s", d
.EndWarning());
518 DescribeHeapAddress(addr
, 1);
519 ReportSummary("bad-free", stack
);
522 void ReportAllocTypeMismatch(uptr addr
, StackTrace
*stack
,
523 AllocType alloc_type
,
524 AllocType dealloc_type
) {
525 static const char *alloc_names
[] =
526 {"INVALID", "malloc", "operator new", "operator new []"};
527 static const char *dealloc_names
[] =
528 {"INVALID", "free", "operator delete", "operator delete []"};
529 CHECK_NE(alloc_type
, dealloc_type
);
530 ScopedInErrorReport in_report
;
532 Printf("%s", d
.Warning());
533 Report("ERROR: AddressSanitizer: alloc-dealloc-mismatch (%s vs %s) on %p\n",
534 alloc_names
[alloc_type
], dealloc_names
[dealloc_type
], addr
);
535 Printf("%s", d
.EndWarning());
537 DescribeHeapAddress(addr
, 1);
538 ReportSummary("alloc-dealloc-mismatch", stack
);
539 Report("HINT: if you don't care about these warnings you may set "
540 "ASAN_OPTIONS=alloc_dealloc_mismatch=0\n");
543 void ReportMallocUsableSizeNotOwned(uptr addr
, StackTrace
*stack
) {
544 ScopedInErrorReport in_report
;
546 Printf("%s", d
.Warning());
547 Report("ERROR: AddressSanitizer: attempting to call "
548 "malloc_usable_size() for pointer which is "
549 "not owned: %p\n", addr
);
550 Printf("%s", d
.EndWarning());
552 DescribeHeapAddress(addr
, 1);
553 ReportSummary("bad-malloc_usable_size", stack
);
556 void ReportAsanGetAllocatedSizeNotOwned(uptr addr
, StackTrace
*stack
) {
557 ScopedInErrorReport in_report
;
559 Printf("%s", d
.Warning());
560 Report("ERROR: AddressSanitizer: attempting to call "
561 "__asan_get_allocated_size() for pointer which is "
562 "not owned: %p\n", addr
);
563 Printf("%s", d
.EndWarning());
565 DescribeHeapAddress(addr
, 1);
566 ReportSummary("bad-__asan_get_allocated_size", stack
);
569 void ReportStringFunctionMemoryRangesOverlap(
570 const char *function
, const char *offset1
, uptr length1
,
571 const char *offset2
, uptr length2
, StackTrace
*stack
) {
572 ScopedInErrorReport in_report
;
575 internal_snprintf(bug_type
, sizeof(bug_type
), "%s-param-overlap", function
);
576 Printf("%s", d
.Warning());
577 Report("ERROR: AddressSanitizer: %s: "
578 "memory ranges [%p,%p) and [%p, %p) overlap\n", \
579 bug_type
, offset1
, offset1
+ length1
, offset2
, offset2
+ length2
);
580 Printf("%s", d
.EndWarning());
582 DescribeAddress((uptr
)offset1
, length1
);
583 DescribeAddress((uptr
)offset2
, length2
);
584 ReportSummary(bug_type
, stack
);
587 // ----------------------- Mac-specific reports ----------------- {{{1
589 void WarnMacFreeUnallocated(
590 uptr addr
, uptr zone_ptr
, const char *zone_name
, StackTrace
*stack
) {
591 // Just print a warning here.
592 Printf("free_common(%p) -- attempting to free unallocated memory.\n"
593 "AddressSanitizer is ignoring this error on Mac OS now.\n",
595 PrintZoneForPointer(addr
, zone_ptr
, zone_name
);
597 DescribeHeapAddress(addr
, 1);
600 void ReportMacMzReallocUnknown(
601 uptr addr
, uptr zone_ptr
, const char *zone_name
, StackTrace
*stack
) {
602 ScopedInErrorReport in_report
;
603 Printf("mz_realloc(%p) -- attempting to realloc unallocated memory.\n"
604 "This is an unrecoverable problem, exiting now.\n",
606 PrintZoneForPointer(addr
, zone_ptr
, zone_name
);
608 DescribeHeapAddress(addr
, 1);
611 void ReportMacCfReallocUnknown(
612 uptr addr
, uptr zone_ptr
, const char *zone_name
, StackTrace
*stack
) {
613 ScopedInErrorReport in_report
;
614 Printf("cf_realloc(%p) -- attempting to realloc unallocated memory.\n"
615 "This is an unrecoverable problem, exiting now.\n",
617 PrintZoneForPointer(addr
, zone_ptr
, zone_name
);
619 DescribeHeapAddress(addr
, 1);
622 } // namespace __asan
624 // --------------------------- Interface --------------------- {{{1
625 using namespace __asan
; // NOLINT
627 void __asan_report_error(uptr pc
, uptr bp
, uptr sp
,
628 uptr addr
, bool is_write
, uptr access_size
) {
629 ScopedInErrorReport in_report
;
631 // Determine the error type.
632 const char *bug_descr
= "unknown-crash";
633 if (AddrIsInMem(addr
)) {
634 u8
*shadow_addr
= (u8
*)MemToShadow(addr
);
635 // If we are accessing 16 bytes, look at the second shadow byte.
636 if (*shadow_addr
== 0 && access_size
> SHADOW_GRANULARITY
)
638 // If we are in the partial right redzone, look at the next shadow byte.
639 if (*shadow_addr
> 0 && *shadow_addr
< 128)
641 switch (*shadow_addr
) {
642 case kAsanHeapLeftRedzoneMagic
:
643 case kAsanHeapRightRedzoneMagic
:
644 bug_descr
= "heap-buffer-overflow";
646 case kAsanHeapFreeMagic
:
647 bug_descr
= "heap-use-after-free";
649 case kAsanStackLeftRedzoneMagic
:
650 bug_descr
= "stack-buffer-underflow";
652 case kAsanInitializationOrderMagic
:
653 bug_descr
= "initialization-order-fiasco";
655 case kAsanStackMidRedzoneMagic
:
656 case kAsanStackRightRedzoneMagic
:
657 case kAsanStackPartialRedzoneMagic
:
658 bug_descr
= "stack-buffer-overflow";
660 case kAsanStackAfterReturnMagic
:
661 bug_descr
= "stack-use-after-return";
663 case kAsanUserPoisonedMemoryMagic
:
664 bug_descr
= "use-after-poison";
666 case kAsanStackUseAfterScopeMagic
:
667 bug_descr
= "stack-use-after-scope";
669 case kAsanGlobalRedzoneMagic
:
670 bug_descr
= "global-buffer-overflow";
675 Printf("%s", d
.Warning());
676 Report("ERROR: AddressSanitizer: %s on address "
677 "%p at pc 0x%zx bp 0x%zx sp 0x%zx\n",
678 bug_descr
, (void*)addr
, pc
, bp
, sp
);
679 Printf("%s", d
.EndWarning());
681 u32 curr_tid
= asanThreadRegistry().GetCurrentTidOrInvalid();
683 Printf("%s%s of size %zu at %p thread T%d%s%s\n",
685 access_size
? (is_write
? "WRITE" : "READ") : "ACCESS",
686 access_size
, (void*)addr
, curr_tid
,
687 ThreadNameWithParenthesis(curr_tid
, tname
, sizeof(tname
)),
690 GET_STACK_TRACE_FATAL(pc
, bp
);
693 DescribeAddress(addr
, access_size
);
694 ReportSummary(bug_descr
, &stack
);
695 PrintShadowMemoryForAddress(addr
);
698 void NOINLINE
__asan_set_error_report_callback(void (*callback
)(const char*)) {
699 error_report_callback
= callback
;
701 error_message_buffer_size
= 1 << 16;
702 error_message_buffer
=
703 (char*)MmapOrDie(error_message_buffer_size
, __FUNCTION__
);
704 error_message_buffer_pos
= 0;
708 void __asan_describe_address(uptr addr
) {
709 DescribeAddress(addr
, 1);
712 #if !SANITIZER_SUPPORTS_WEAK_HOOKS
713 // Provide default implementation of __asan_on_error that does nothing
714 // and may be overriden by user.
715 SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE NOINLINE
716 void __asan_on_error() {}