1 //===-- asan_report.cc ----------------------------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file is a part of AddressSanitizer, an address sanity checker.
12 // This file contains error reporting code.
13 //===----------------------------------------------------------------------===//
15 #include "asan_flags.h"
16 #include "asan_internal.h"
17 #include "asan_mapping.h"
18 #include "asan_report.h"
19 #include "asan_scariness_score.h"
20 #include "asan_stack.h"
21 #include "asan_thread.h"
22 #include "sanitizer_common/sanitizer_common.h"
23 #include "sanitizer_common/sanitizer_flags.h"
24 #include "sanitizer_common/sanitizer_report_decorator.h"
25 #include "sanitizer_common/sanitizer_stackdepot.h"
26 #include "sanitizer_common/sanitizer_symbolizer.h"
30 // -------------------- User-specified callbacks ----------------- {{{1
31 static void (*error_report_callback
)(const char*);
32 static char *error_message_buffer
= nullptr;
33 static uptr error_message_buffer_pos
= 0;
34 static BlockingMutex
error_message_buf_mutex(LINKER_INITIALIZED
);
35 static const unsigned kAsanBuggyPcPoolSize
= 25;
36 static __sanitizer::atomic_uintptr_t AsanBuggyPcPool
[kAsanBuggyPcPoolSize
];
45 const char *description
;
48 static bool report_happened
= false;
49 static ReportData report_data
= {};
51 void AppendToErrorMessageBuffer(const char *buffer
) {
52 BlockingMutexLock
l(&error_message_buf_mutex
);
53 if (!error_message_buffer
) {
54 error_message_buffer
=
55 (char*)MmapOrDieQuietly(kErrorMessageBufferSize
, __func__
);
56 error_message_buffer_pos
= 0;
58 uptr length
= internal_strlen(buffer
);
59 RAW_CHECK(kErrorMessageBufferSize
>= error_message_buffer_pos
);
60 uptr remaining
= kErrorMessageBufferSize
- error_message_buffer_pos
;
61 internal_strncpy(error_message_buffer
+ error_message_buffer_pos
,
63 error_message_buffer
[kErrorMessageBufferSize
- 1] = '\0';
64 // FIXME: reallocate the buffer instead of truncating the message.
65 error_message_buffer_pos
+= Min(remaining
, length
);
68 // ---------------------- Decorator ------------------------------ {{{1
69 class Decorator
: public __sanitizer::SanitizerCommonDecorator
{
71 Decorator() : SanitizerCommonDecorator() { }
72 const char *Access() { return Blue(); }
73 const char *EndAccess() { return Default(); }
74 const char *Location() { return Green(); }
75 const char *EndLocation() { return Default(); }
76 const char *Allocation() { return Magenta(); }
77 const char *EndAllocation() { return Default(); }
79 const char *ShadowByte(u8 byte
) {
81 case kAsanHeapLeftRedzoneMagic
:
82 case kAsanHeapRightRedzoneMagic
:
83 case kAsanArrayCookieMagic
:
85 case kAsanHeapFreeMagic
:
87 case kAsanStackLeftRedzoneMagic
:
88 case kAsanStackMidRedzoneMagic
:
89 case kAsanStackRightRedzoneMagic
:
90 case kAsanStackPartialRedzoneMagic
:
92 case kAsanStackAfterReturnMagic
:
94 case kAsanInitializationOrderMagic
:
96 case kAsanUserPoisonedMemoryMagic
:
97 case kAsanContiguousContainerOOBMagic
:
98 case kAsanAllocaLeftMagic
:
99 case kAsanAllocaRightMagic
:
101 case kAsanStackUseAfterScopeMagic
:
103 case kAsanGlobalRedzoneMagic
:
105 case kAsanInternalHeapMagic
:
107 case kAsanIntraObjectRedzone
:
113 const char *EndShadowByte() { return Default(); }
114 const char *MemoryByte() { return Magenta(); }
115 const char *EndMemoryByte() { return Default(); }
118 // ---------------------- Helper functions ----------------------- {{{1
120 static void PrintMemoryByte(InternalScopedString
*str
, const char *before
,
121 u8 byte
, bool in_shadow
, const char *after
= "\n") {
123 str
->append("%s%s%x%x%s%s", before
,
124 in_shadow
? d
.ShadowByte(byte
) : d
.MemoryByte(),
125 byte
>> 4, byte
& 15,
126 in_shadow
? d
.EndShadowByte() : d
.EndMemoryByte(), after
);
129 static void PrintShadowByte(InternalScopedString
*str
, const char *before
,
130 u8 byte
, const char *after
= "\n") {
131 PrintMemoryByte(str
, before
, byte
, /*in_shadow*/true, after
);
134 static void PrintShadowBytes(InternalScopedString
*str
, const char *before
,
135 u8
*bytes
, u8
*guilty
, uptr n
) {
137 if (before
) str
->append("%s%p:", before
, bytes
);
138 for (uptr i
= 0; i
< n
; i
++) {
141 p
== guilty
? "[" : (p
- 1 == guilty
&& i
!= 0) ? "" : " ";
142 const char *after
= p
== guilty
? "]" : "";
143 PrintShadowByte(str
, before
, *p
, after
);
148 static void PrintLegend(InternalScopedString
*str
) {
150 "Shadow byte legend (one shadow byte represents %d "
151 "application bytes):\n",
152 (int)SHADOW_GRANULARITY
);
153 PrintShadowByte(str
, " Addressable: ", 0);
154 str
->append(" Partially addressable: ");
155 for (u8 i
= 1; i
< SHADOW_GRANULARITY
; i
++) PrintShadowByte(str
, "", i
, " ");
157 PrintShadowByte(str
, " Heap left redzone: ",
158 kAsanHeapLeftRedzoneMagic
);
159 PrintShadowByte(str
, " Heap right redzone: ",
160 kAsanHeapRightRedzoneMagic
);
161 PrintShadowByte(str
, " Freed heap region: ", kAsanHeapFreeMagic
);
162 PrintShadowByte(str
, " Stack left redzone: ",
163 kAsanStackLeftRedzoneMagic
);
164 PrintShadowByte(str
, " Stack mid redzone: ",
165 kAsanStackMidRedzoneMagic
);
166 PrintShadowByte(str
, " Stack right redzone: ",
167 kAsanStackRightRedzoneMagic
);
168 PrintShadowByte(str
, " Stack partial redzone: ",
169 kAsanStackPartialRedzoneMagic
);
170 PrintShadowByte(str
, " Stack after return: ",
171 kAsanStackAfterReturnMagic
);
172 PrintShadowByte(str
, " Stack use after scope: ",
173 kAsanStackUseAfterScopeMagic
);
174 PrintShadowByte(str
, " Global redzone: ", kAsanGlobalRedzoneMagic
);
175 PrintShadowByte(str
, " Global init order: ",
176 kAsanInitializationOrderMagic
);
177 PrintShadowByte(str
, " Poisoned by user: ",
178 kAsanUserPoisonedMemoryMagic
);
179 PrintShadowByte(str
, " Container overflow: ",
180 kAsanContiguousContainerOOBMagic
);
181 PrintShadowByte(str
, " Array cookie: ",
182 kAsanArrayCookieMagic
);
183 PrintShadowByte(str
, " Intra object redzone: ",
184 kAsanIntraObjectRedzone
);
185 PrintShadowByte(str
, " ASan internal: ", kAsanInternalHeapMagic
);
186 PrintShadowByte(str
, " Left alloca redzone: ", kAsanAllocaLeftMagic
);
187 PrintShadowByte(str
, " Right alloca redzone: ", kAsanAllocaRightMagic
);
190 void MaybeDumpInstructionBytes(uptr pc
) {
191 if (!flags()->dump_instruction_bytes
|| (pc
< GetPageSizeCached()))
193 InternalScopedString
str(1024);
194 str
.append("First 16 instruction bytes at pc: ");
195 if (IsAccessibleMemoryRange(pc
, 16)) {
196 for (int i
= 0; i
< 16; ++i
) {
197 PrintMemoryByte(&str
, "", ((u8
*)pc
)[i
], /*in_shadow*/false, " ");
201 str
.append("unaccessible\n");
203 Report("%s", str
.data());
206 static void PrintShadowMemoryForAddress(uptr addr
) {
207 if (!AddrIsInMem(addr
)) return;
208 uptr shadow_addr
= MemToShadow(addr
);
209 const uptr n_bytes_per_row
= 16;
210 uptr aligned_shadow
= shadow_addr
& ~(n_bytes_per_row
- 1);
211 InternalScopedString
str(4096 * 8);
212 str
.append("Shadow bytes around the buggy address:\n");
213 for (int i
= -5; i
<= 5; i
++) {
214 const char *prefix
= (i
== 0) ? "=>" : " ";
215 PrintShadowBytes(&str
, prefix
, (u8
*)(aligned_shadow
+ i
* n_bytes_per_row
),
216 (u8
*)shadow_addr
, n_bytes_per_row
);
218 if (flags()->print_legend
) PrintLegend(&str
);
219 Printf("%s", str
.data());
222 static void PrintZoneForPointer(uptr ptr
, uptr zone_ptr
,
223 const char *zone_name
) {
226 Printf("malloc_zone_from_ptr(%p) = %p, which is %s\n",
227 ptr
, zone_ptr
, zone_name
);
229 Printf("malloc_zone_from_ptr(%p) = %p, which doesn't have a name\n",
233 Printf("malloc_zone_from_ptr(%p) = 0\n", ptr
);
237 static void DescribeThread(AsanThread
*t
) {
239 DescribeThread(t
->context());
242 // ---------------------- Address Descriptions ------------------- {{{1
244 static bool IsASCII(unsigned char c
) {
245 return /*0x00 <= c &&*/ c
<= 0x7F;
248 static const char *MaybeDemangleGlobalName(const char *name
) {
249 // We can spoil names of globals with C linkage, so use an heuristic
250 // approach to check if the name should be demangled.
251 bool should_demangle
= false;
252 if (name
[0] == '_' && name
[1] == 'Z')
253 should_demangle
= true;
254 else if (SANITIZER_WINDOWS
&& name
[0] == '\01' && name
[1] == '?')
255 should_demangle
= true;
257 return should_demangle
? Symbolizer::GetOrInit()->Demangle(name
) : name
;
260 // Check if the global is a zero-terminated ASCII string. If so, print it.
261 static void PrintGlobalNameIfASCII(InternalScopedString
*str
,
262 const __asan_global
&g
) {
263 for (uptr p
= g
.beg
; p
< g
.beg
+ g
.size
- 1; p
++) {
264 unsigned char c
= *(unsigned char*)p
;
265 if (c
== '\0' || !IsASCII(c
)) return;
267 if (*(char*)(g
.beg
+ g
.size
- 1) != '\0') return;
268 str
->append(" '%s' is ascii string '%s'\n", MaybeDemangleGlobalName(g
.name
),
272 static const char *GlobalFilename(const __asan_global
&g
) {
273 const char *res
= g
.module_name
;
274 // Prefer the filename from source location, if is available.
276 res
= g
.location
->filename
;
281 static void PrintGlobalLocation(InternalScopedString
*str
,
282 const __asan_global
&g
) {
283 str
->append("%s", GlobalFilename(g
));
286 if (g
.location
->line_no
)
287 str
->append(":%d", g
.location
->line_no
);
288 if (g
.location
->column_no
)
289 str
->append(":%d", g
.location
->column_no
);
292 static void DescribeAddressRelativeToGlobal(uptr addr
, uptr size
,
293 const __asan_global
&g
) {
294 InternalScopedString
str(4096);
296 str
.append("%s", d
.Location());
298 str
.append("%p is located %zd bytes to the left", (void *)addr
,
300 } else if (addr
+ size
> g
.beg
+ g
.size
) {
301 if (addr
< g
.beg
+ g
.size
)
302 addr
= g
.beg
+ g
.size
;
303 str
.append("%p is located %zd bytes to the right", (void *)addr
,
304 addr
- (g
.beg
+ g
.size
));
307 str
.append("%p is located %zd bytes inside", (void *)addr
, addr
- g
.beg
);
309 str
.append(" of global variable '%s' defined in '",
310 MaybeDemangleGlobalName(g
.name
));
311 PrintGlobalLocation(&str
, g
);
312 str
.append("' (0x%zx) of size %zu\n", g
.beg
, g
.size
);
313 str
.append("%s", d
.EndLocation());
314 PrintGlobalNameIfASCII(&str
, g
);
315 Printf("%s", str
.data());
318 static bool DescribeAddressIfGlobal(uptr addr
, uptr size
,
319 const char *bug_type
) {
320 // Assume address is close to at most four globals.
321 const int kMaxGlobalsInReport
= 4;
322 __asan_global globals
[kMaxGlobalsInReport
];
323 u32 reg_sites
[kMaxGlobalsInReport
];
325 GetGlobalsForAddress(addr
, globals
, reg_sites
, ARRAY_SIZE(globals
));
326 if (globals_num
== 0)
328 for (int i
= 0; i
< globals_num
; i
++) {
329 DescribeAddressRelativeToGlobal(addr
, size
, globals
[i
]);
330 if (0 == internal_strcmp(bug_type
, "initialization-order-fiasco") &&
332 Printf(" registered at:\n");
333 StackDepotGet(reg_sites
[i
]).Print();
339 bool DescribeAddressIfShadow(uptr addr
, AddressDescription
*descr
, bool print
) {
340 if (AddrIsInMem(addr
))
342 const char *area_type
= nullptr;
343 if (AddrIsInShadowGap(addr
)) area_type
= "shadow gap";
344 else if (AddrIsInHighShadow(addr
)) area_type
= "high shadow";
345 else if (AddrIsInLowShadow(addr
)) area_type
= "low shadow";
346 if (area_type
!= nullptr) {
348 Printf("Address %p is located in the %s area.\n", addr
, area_type
);
351 descr
->region_kind
= area_type
;
355 CHECK(0 && "Address is not in memory and not in shadow?");
359 // Return " (thread_name) " or an empty string if the name is empty.
360 const char *ThreadNameWithParenthesis(AsanThreadContext
*t
, char buff
[],
362 const char *name
= t
->name
;
363 if (name
[0] == '\0') return "";
365 internal_strncat(buff
, " (", 3);
366 internal_strncat(buff
, name
, buff_len
- 4);
367 internal_strncat(buff
, ")", 2);
371 const char *ThreadNameWithParenthesis(u32 tid
, char buff
[],
373 if (tid
== kInvalidTid
) return "";
374 asanThreadRegistry().CheckLocked();
375 AsanThreadContext
*t
= GetThreadContextByTidLocked(tid
);
376 return ThreadNameWithParenthesis(t
, buff
, buff_len
);
379 static void PrintAccessAndVarIntersection(const StackVarDescr
&var
, uptr addr
,
380 uptr access_size
, uptr prev_var_end
,
382 uptr var_end
= var
.beg
+ var
.size
;
383 uptr addr_end
= addr
+ access_size
;
384 const char *pos_descr
= nullptr;
385 // If the variable [var.beg, var_end) is the nearest variable to the
386 // current memory access, indicate it in the log.
387 if (addr
>= var
.beg
) {
388 if (addr_end
<= var_end
)
389 pos_descr
= "is inside"; // May happen if this is a use-after-return.
390 else if (addr
< var_end
)
391 pos_descr
= "partially overflows";
392 else if (addr_end
<= next_var_beg
&&
393 next_var_beg
- addr_end
>= addr
- var_end
)
394 pos_descr
= "overflows";
396 if (addr_end
> var
.beg
)
397 pos_descr
= "partially underflows";
398 else if (addr
>= prev_var_end
&&
399 addr
- prev_var_end
>= var
.beg
- addr_end
)
400 pos_descr
= "underflows";
402 InternalScopedString
str(1024);
403 str
.append(" [%zd, %zd)", var
.beg
, var_end
);
404 // Render variable name.
406 for (uptr i
= 0; i
< var
.name_len
; ++i
) {
407 str
.append("%c", var
.name_pos
[i
]);
412 // FIXME: we may want to also print the size of the access here,
413 // but in case of accesses generated by memset it may be confusing.
414 str
.append("%s <== Memory access at offset %zd %s this variable%s\n",
415 d
.Location(), addr
, pos_descr
, d
.EndLocation());
419 Printf("%s", str
.data());
422 bool ParseFrameDescription(const char *frame_descr
,
423 InternalMmapVector
<StackVarDescr
> *vars
) {
426 // This string is created by the compiler and has the following form:
427 // "n alloc_1 alloc_2 ... alloc_n"
428 // where alloc_i looks like "offset size len ObjectName".
429 uptr n_objects
= (uptr
)internal_simple_strtoll(frame_descr
, &p
, 10);
433 for (uptr i
= 0; i
< n_objects
; i
++) {
434 uptr beg
= (uptr
)internal_simple_strtoll(p
, &p
, 10);
435 uptr size
= (uptr
)internal_simple_strtoll(p
, &p
, 10);
436 uptr len
= (uptr
)internal_simple_strtoll(p
, &p
, 10);
437 if (beg
== 0 || size
== 0 || *p
!= ' ') {
441 StackVarDescr var
= {beg
, size
, p
, len
};
442 vars
->push_back(var
);
449 bool DescribeAddressIfStack(uptr addr
, uptr access_size
) {
450 AsanThread
*t
= FindThreadByStackAddress(addr
);
451 if (!t
) return false;
455 Printf("%s", d
.Location());
456 Printf("Address %p is located in stack of thread T%d%s", addr
, t
->tid(),
457 ThreadNameWithParenthesis(t
->tid(), tname
, sizeof(tname
)));
459 // Try to fetch precise stack frame for this access.
460 AsanThread::StackFrameAccess access
;
461 if (!t
->GetStackFrameAccessByAddr(addr
, &access
)) {
462 Printf("%s\n", d
.EndLocation());
465 Printf(" at offset %zu in frame%s\n", access
.offset
, d
.EndLocation());
467 // Now we print the frame where the alloca has happened.
468 // We print this frame as a stack trace with one element.
469 // The symbolizer may print more than one frame if inlining was involved.
470 // The frame numbers may be different than those in the stack trace printed
471 // previously. That's unfortunate, but I have no better solution,
472 // especially given that the alloca may be from entirely different place
473 // (e.g. use-after-scope, or different thread's stack).
474 #if SANITIZER_PPC64V1
475 // On PowerPC64 ELFv1, the address of a function actually points to a
476 // three-doubleword data structure with the first field containing
477 // the address of the function's code.
478 access
.frame_pc
= *reinterpret_cast<uptr
*>(access
.frame_pc
);
480 access
.frame_pc
+= 16;
481 Printf("%s", d
.EndLocation());
482 StackTrace
alloca_stack(&access
.frame_pc
, 1);
483 alloca_stack
.Print();
485 InternalMmapVector
<StackVarDescr
> vars(16);
486 if (!ParseFrameDescription(access
.frame_descr
, &vars
)) {
487 Printf("AddressSanitizer can't parse the stack frame "
488 "descriptor: |%s|\n", access
.frame_descr
);
489 // 'addr' is a stack address, so return true even if we can't parse frame
492 uptr n_objects
= vars
.size();
493 // Report the number of stack objects.
494 Printf(" This frame has %zu object(s):\n", n_objects
);
496 // Report all objects in this frame.
497 for (uptr i
= 0; i
< n_objects
; i
++) {
498 uptr prev_var_end
= i
? vars
[i
- 1].beg
+ vars
[i
- 1].size
: 0;
499 uptr next_var_beg
= i
+ 1 < n_objects
? vars
[i
+ 1].beg
: ~(0UL);
500 PrintAccessAndVarIntersection(vars
[i
], access
.offset
, access_size
,
501 prev_var_end
, next_var_beg
);
503 Printf("HINT: this may be a false positive if your program uses "
504 "some custom stack unwind mechanism or swapcontext\n");
505 if (SANITIZER_WINDOWS
)
506 Printf(" (longjmp, SEH and C++ exceptions *are* supported)\n");
508 Printf(" (longjmp and C++ exceptions *are* supported)\n");
514 static void DescribeAccessToHeapChunk(AsanChunkView chunk
, uptr addr
,
518 InternalScopedString
str(4096);
519 str
.append("%s", d
.Location());
520 if (chunk
.AddrIsAtLeft(addr
, access_size
, &offset
)) {
521 str
.append("%p is located %zd bytes to the left of", (void *)addr
, offset
);
522 } else if (chunk
.AddrIsAtRight(addr
, access_size
, &offset
)) {
527 str
.append("%p is located %zd bytes to the right of", (void *)addr
, offset
);
528 } else if (chunk
.AddrIsInside(addr
, access_size
, &offset
)) {
529 str
.append("%p is located %zd bytes inside of", (void*)addr
, offset
);
531 str
.append("%p is located somewhere around (this is AddressSanitizer bug!)",
534 str
.append(" %zu-byte region [%p,%p)\n", chunk
.UsedSize(),
535 (void *)(chunk
.Beg()), (void *)(chunk
.End()));
536 str
.append("%s", d
.EndLocation());
537 Printf("%s", str
.data());
540 void DescribeHeapAddress(uptr addr
, uptr access_size
) {
541 AsanChunkView chunk
= FindHeapChunkByAddress(addr
);
542 if (!chunk
.IsValid()) {
543 Printf("AddressSanitizer can not describe address in more detail "
544 "(wild memory access suspected).\n");
547 DescribeAccessToHeapChunk(chunk
, addr
, access_size
);
548 CHECK(chunk
.AllocTid() != kInvalidTid
);
549 asanThreadRegistry().CheckLocked();
550 AsanThreadContext
*alloc_thread
=
551 GetThreadContextByTidLocked(chunk
.AllocTid());
552 StackTrace alloc_stack
= chunk
.GetAllocStack();
555 AsanThreadContext
*free_thread
= nullptr;
556 if (chunk
.FreeTid() != kInvalidTid
) {
557 free_thread
= GetThreadContextByTidLocked(chunk
.FreeTid());
558 Printf("%sfreed by thread T%d%s here:%s\n", d
.Allocation(),
560 ThreadNameWithParenthesis(free_thread
, tname
, sizeof(tname
)),
562 StackTrace free_stack
= chunk
.GetFreeStack();
564 Printf("%spreviously allocated by thread T%d%s here:%s\n",
565 d
.Allocation(), alloc_thread
->tid
,
566 ThreadNameWithParenthesis(alloc_thread
, tname
, sizeof(tname
)),
569 Printf("%sallocated by thread T%d%s here:%s\n", d
.Allocation(),
571 ThreadNameWithParenthesis(alloc_thread
, tname
, sizeof(tname
)),
575 DescribeThread(GetCurrentThread());
577 DescribeThread(free_thread
);
578 DescribeThread(alloc_thread
);
581 static void DescribeAddress(uptr addr
, uptr access_size
, const char *bug_type
) {
582 // Check if this is shadow or shadow gap.
583 if (DescribeAddressIfShadow(addr
))
585 CHECK(AddrIsInMem(addr
));
586 if (DescribeAddressIfGlobal(addr
, access_size
, bug_type
))
588 if (DescribeAddressIfStack(addr
, access_size
))
590 // Assume it is a heap address.
591 DescribeHeapAddress(addr
, access_size
);
594 // ------------------- Thread description -------------------- {{{1
596 void DescribeThread(AsanThreadContext
*context
) {
598 asanThreadRegistry().CheckLocked();
599 // No need to announce the main thread.
600 if (context
->tid
== 0 || context
->announced
) {
603 context
->announced
= true;
605 InternalScopedString
str(1024);
606 str
.append("Thread T%d%s", context
->tid
,
607 ThreadNameWithParenthesis(context
->tid
, tname
, sizeof(tname
)));
608 if (context
->parent_tid
== kInvalidTid
) {
609 str
.append(" created by unknown thread\n");
610 Printf("%s", str
.data());
614 " created by T%d%s here:\n", context
->parent_tid
,
615 ThreadNameWithParenthesis(context
->parent_tid
, tname
, sizeof(tname
)));
616 Printf("%s", str
.data());
617 StackDepotGet(context
->stack_id
).Print();
618 // Recursively described parent thread if needed.
619 if (flags()->print_full_thread_history
) {
620 AsanThreadContext
*parent_context
=
621 GetThreadContextByTidLocked(context
->parent_tid
);
622 DescribeThread(parent_context
);
626 // -------------------- Different kinds of reports ----------------- {{{1
628 // Use ScopedInErrorReport to run common actions just before and
629 // immediately after printing error report.
630 class ScopedInErrorReport
{
632 explicit ScopedInErrorReport(ReportData
*report
= nullptr,
633 bool fatal
= false) {
634 halt_on_error_
= fatal
|| flags()->halt_on_error
;
636 if (lock_
.TryLock()) {
637 StartReporting(report
);
641 // ASan found two bugs in different threads simultaneously.
643 u32 current_tid
= GetCurrentTidOrInvalid();
644 if (reporting_thread_tid_
== current_tid
||
645 reporting_thread_tid_
== kInvalidTid
) {
646 // This is either asynch signal or nested error during error reporting.
647 // Fail simple to avoid deadlocks in Report().
649 // Can't use Report() here because of potential deadlocks
650 // in nested signal handlers.
651 const char msg
[] = "AddressSanitizer: nested bug in the same thread, "
653 WriteToFile(kStderrFd
, msg
, sizeof(msg
));
655 internal__exit(common_flags()->exitcode
);
658 if (halt_on_error_
) {
659 // Do not print more than one report, otherwise they will mix up.
660 // Error reporting functions shouldn't return at this situation, as
661 // they are effectively no-returns.
663 Report("AddressSanitizer: while reporting a bug found another one. "
666 // Sleep long enough to make sure that the thread which started
667 // to print an error report will finish doing it.
668 SleepForSeconds(Max(100, flags()->sleep_before_dying
+ 1));
670 // If we're still not dead for some reason, use raw _exit() instead of
671 // Die() to bypass any additional checks.
672 internal__exit(common_flags()->exitcode
);
674 // The other thread will eventually finish reporting
675 // so it's safe to wait
679 StartReporting(report
);
682 ~ScopedInErrorReport() {
683 // Make sure the current thread is announced.
684 DescribeThread(GetCurrentThread());
685 // We may want to grab this lock again when printing stats.
686 asanThreadRegistry().Unlock();
687 // Print memory stats.
688 if (flags()->print_stats
)
689 __asan_print_accumulated_stats();
691 if (common_flags()->print_cmdline
)
694 // Copy the message buffer so that we could start logging without holding a
695 // lock that gets aquired during printing.
696 InternalScopedBuffer
<char> buffer_copy(kErrorMessageBufferSize
);
698 BlockingMutexLock
l(&error_message_buf_mutex
);
699 internal_memcpy(buffer_copy
.data(),
700 error_message_buffer
, kErrorMessageBufferSize
);
703 LogFullErrorReport(buffer_copy
.data());
705 if (error_report_callback
) {
706 error_report_callback(buffer_copy
.data());
708 CommonSanitizerReportMutex
.Unlock();
709 reporting_thread_tid_
= kInvalidTid
;
711 if (halt_on_error_
) {
712 Report("ABORTING\n");
718 void StartReporting(ReportData
*report
) {
719 if (report
) report_data
= *report
;
720 report_happened
= true;
722 // Make sure the registry and sanitizer report mutexes are locked while
723 // we're printing an error report.
724 // We can lock them only here to avoid self-deadlock in case of
725 // recursive reports.
726 asanThreadRegistry().Lock();
727 CommonSanitizerReportMutex
.Lock();
728 reporting_thread_tid_
= GetCurrentTidOrInvalid();
729 Printf("===================================================="
733 static StaticSpinMutex lock_
;
734 static u32 reporting_thread_tid_
;
738 StaticSpinMutex
ScopedInErrorReport::lock_
;
739 u32
ScopedInErrorReport::reporting_thread_tid_
= kInvalidTid
;
741 void ReportStackOverflow(const SignalContext
&sig
) {
742 ScopedInErrorReport
in_report(/*report*/ nullptr, /*fatal*/ true);
744 Printf("%s", d
.Warning());
746 "ERROR: AddressSanitizer: stack-overflow on address %p"
747 " (pc %p bp %p sp %p T%d)\n",
748 (void *)sig
.addr
, (void *)sig
.pc
, (void *)sig
.bp
, (void *)sig
.sp
,
749 GetCurrentTidOrInvalid());
750 Printf("%s", d
.EndWarning());
751 ScarinessScore::PrintSimple(10, "stack-overflow");
752 GET_STACK_TRACE_SIGNAL(sig
);
754 ReportErrorSummary("stack-overflow", &stack
);
757 void ReportDeadlySignal(const char *description
, const SignalContext
&sig
) {
758 ScopedInErrorReport
in_report(/*report*/ nullptr, /*fatal*/ true);
760 Printf("%s", d
.Warning());
762 "ERROR: AddressSanitizer: %s on unknown address %p"
763 " (pc %p bp %p sp %p T%d)\n",
764 description
, (void *)sig
.addr
, (void *)sig
.pc
, (void *)sig
.bp
,
765 (void *)sig
.sp
, GetCurrentTidOrInvalid());
766 Printf("%s", d
.EndWarning());
768 if (sig
.pc
< GetPageSizeCached())
769 Report("Hint: pc points to the zero page.\n");
770 if (sig
.is_memory_access
) {
771 const char *access_type
=
772 sig
.write_flag
== SignalContext::WRITE
774 : (sig
.write_flag
== SignalContext::READ
? "READ" : "UNKNOWN");
775 Report("The signal is caused by a %s memory access.\n", access_type
);
776 if (sig
.addr
< GetPageSizeCached()) {
777 Report("Hint: address points to the zero page.\n");
778 SS
.Scare(10, "null-deref");
779 } else if (sig
.addr
== sig
.pc
) {
780 SS
.Scare(60, "wild-jump");
781 } else if (sig
.write_flag
== SignalContext::WRITE
) {
782 SS
.Scare(30, "wild-addr-write");
783 } else if (sig
.write_flag
== SignalContext::READ
) {
784 SS
.Scare(20, "wild-addr-read");
786 SS
.Scare(25, "wild-addr");
789 SS
.Scare(10, "signal");
792 GET_STACK_TRACE_SIGNAL(sig
);
794 MaybeDumpInstructionBytes(sig
.pc
);
795 Printf("AddressSanitizer can not provide additional info.\n");
796 ReportErrorSummary(description
, &stack
);
799 void ReportDoubleFree(uptr addr
, BufferedStackTrace
*free_stack
) {
800 ScopedInErrorReport in_report
;
802 Printf("%s", d
.Warning());
804 u32 curr_tid
= GetCurrentTidOrInvalid();
805 Report("ERROR: AddressSanitizer: attempting double-free on %p in "
808 ThreadNameWithParenthesis(curr_tid
, tname
, sizeof(tname
)));
809 Printf("%s", d
.EndWarning());
810 CHECK_GT(free_stack
->size
, 0);
811 ScarinessScore::PrintSimple(42, "double-free");
812 GET_STACK_TRACE_FATAL(free_stack
->trace
[0], free_stack
->top_frame_bp
);
814 DescribeHeapAddress(addr
, 1);
815 ReportErrorSummary("double-free", &stack
);
818 void ReportNewDeleteSizeMismatch(uptr addr
, uptr alloc_size
, uptr delete_size
,
819 BufferedStackTrace
*free_stack
) {
820 ScopedInErrorReport in_report
;
822 Printf("%s", d
.Warning());
824 u32 curr_tid
= GetCurrentTidOrInvalid();
825 Report("ERROR: AddressSanitizer: new-delete-type-mismatch on %p in "
828 ThreadNameWithParenthesis(curr_tid
, tname
, sizeof(tname
)));
829 Printf("%s object passed to delete has wrong type:\n", d
.EndWarning());
830 Printf(" size of the allocated type: %zd bytes;\n"
831 " size of the deallocated type: %zd bytes.\n",
832 alloc_size
, delete_size
);
833 CHECK_GT(free_stack
->size
, 0);
834 ScarinessScore::PrintSimple(10, "new-delete-type-mismatch");
835 GET_STACK_TRACE_FATAL(free_stack
->trace
[0], free_stack
->top_frame_bp
);
837 DescribeHeapAddress(addr
, 1);
838 ReportErrorSummary("new-delete-type-mismatch", &stack
);
839 Report("HINT: if you don't care about these errors you may set "
840 "ASAN_OPTIONS=new_delete_type_mismatch=0\n");
843 void ReportFreeNotMalloced(uptr addr
, BufferedStackTrace
*free_stack
) {
844 ScopedInErrorReport in_report
;
846 Printf("%s", d
.Warning());
848 u32 curr_tid
= GetCurrentTidOrInvalid();
849 Report("ERROR: AddressSanitizer: attempting free on address "
850 "which was not malloc()-ed: %p in thread T%d%s\n", addr
,
851 curr_tid
, ThreadNameWithParenthesis(curr_tid
, tname
, sizeof(tname
)));
852 Printf("%s", d
.EndWarning());
853 CHECK_GT(free_stack
->size
, 0);
854 ScarinessScore::PrintSimple(40, "bad-free");
855 GET_STACK_TRACE_FATAL(free_stack
->trace
[0], free_stack
->top_frame_bp
);
857 DescribeHeapAddress(addr
, 1);
858 ReportErrorSummary("bad-free", &stack
);
861 void ReportAllocTypeMismatch(uptr addr
, BufferedStackTrace
*free_stack
,
862 AllocType alloc_type
,
863 AllocType dealloc_type
) {
864 static const char *alloc_names
[] =
865 {"INVALID", "malloc", "operator new", "operator new []"};
866 static const char *dealloc_names
[] =
867 {"INVALID", "free", "operator delete", "operator delete []"};
868 CHECK_NE(alloc_type
, dealloc_type
);
869 ScopedInErrorReport in_report
;
871 Printf("%s", d
.Warning());
872 Report("ERROR: AddressSanitizer: alloc-dealloc-mismatch (%s vs %s) on %p\n",
873 alloc_names
[alloc_type
], dealloc_names
[dealloc_type
], addr
);
874 Printf("%s", d
.EndWarning());
875 CHECK_GT(free_stack
->size
, 0);
876 ScarinessScore::PrintSimple(10, "alloc-dealloc-mismatch");
877 GET_STACK_TRACE_FATAL(free_stack
->trace
[0], free_stack
->top_frame_bp
);
879 DescribeHeapAddress(addr
, 1);
880 ReportErrorSummary("alloc-dealloc-mismatch", &stack
);
881 Report("HINT: if you don't care about these errors you may set "
882 "ASAN_OPTIONS=alloc_dealloc_mismatch=0\n");
885 void ReportMallocUsableSizeNotOwned(uptr addr
, BufferedStackTrace
*stack
) {
886 ScopedInErrorReport in_report
;
888 Printf("%s", d
.Warning());
889 Report("ERROR: AddressSanitizer: attempting to call "
890 "malloc_usable_size() for pointer which is "
891 "not owned: %p\n", addr
);
892 Printf("%s", d
.EndWarning());
894 DescribeHeapAddress(addr
, 1);
895 ReportErrorSummary("bad-malloc_usable_size", stack
);
898 void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr
,
899 BufferedStackTrace
*stack
) {
900 ScopedInErrorReport in_report
;
902 Printf("%s", d
.Warning());
903 Report("ERROR: AddressSanitizer: attempting to call "
904 "__sanitizer_get_allocated_size() for pointer which is "
905 "not owned: %p\n", addr
);
906 Printf("%s", d
.EndWarning());
908 DescribeHeapAddress(addr
, 1);
909 ReportErrorSummary("bad-__sanitizer_get_allocated_size", stack
);
912 void ReportStringFunctionMemoryRangesOverlap(const char *function
,
913 const char *offset1
, uptr length1
,
914 const char *offset2
, uptr length2
,
915 BufferedStackTrace
*stack
) {
916 ScopedInErrorReport in_report
;
919 internal_snprintf(bug_type
, sizeof(bug_type
), "%s-param-overlap", function
);
920 Printf("%s", d
.Warning());
921 Report("ERROR: AddressSanitizer: %s: "
922 "memory ranges [%p,%p) and [%p, %p) overlap\n", \
923 bug_type
, offset1
, offset1
+ length1
, offset2
, offset2
+ length2
);
924 Printf("%s", d
.EndWarning());
925 ScarinessScore::PrintSimple(10, bug_type
);
927 DescribeAddress((uptr
)offset1
, length1
, bug_type
);
928 DescribeAddress((uptr
)offset2
, length2
, bug_type
);
929 ReportErrorSummary(bug_type
, stack
);
932 void ReportStringFunctionSizeOverflow(uptr offset
, uptr size
,
933 BufferedStackTrace
*stack
) {
934 ScopedInErrorReport in_report
;
936 const char *bug_type
= "negative-size-param";
937 Printf("%s", d
.Warning());
938 Report("ERROR: AddressSanitizer: %s: (size=%zd)\n", bug_type
, size
);
939 Printf("%s", d
.EndWarning());
940 ScarinessScore::PrintSimple(10, bug_type
);
942 DescribeAddress(offset
, size
, bug_type
);
943 ReportErrorSummary(bug_type
, stack
);
946 void ReportBadParamsToAnnotateContiguousContainer(uptr beg
, uptr end
,
947 uptr old_mid
, uptr new_mid
,
948 BufferedStackTrace
*stack
) {
949 ScopedInErrorReport in_report
;
950 Report("ERROR: AddressSanitizer: bad parameters to "
951 "__sanitizer_annotate_contiguous_container:\n"
956 beg
, end
, old_mid
, new_mid
);
957 uptr granularity
= SHADOW_GRANULARITY
;
958 if (!IsAligned(beg
, granularity
))
959 Report("ERROR: beg is not aligned by %d\n", granularity
);
961 ReportErrorSummary("bad-__sanitizer_annotate_contiguous_container", stack
);
964 void ReportODRViolation(const __asan_global
*g1
, u32 stack_id1
,
965 const __asan_global
*g2
, u32 stack_id2
) {
966 ScopedInErrorReport in_report
;
968 Printf("%s", d
.Warning());
969 Report("ERROR: AddressSanitizer: odr-violation (%p):\n", g1
->beg
);
970 Printf("%s", d
.EndWarning());
971 InternalScopedString
g1_loc(256), g2_loc(256);
972 PrintGlobalLocation(&g1_loc
, *g1
);
973 PrintGlobalLocation(&g2_loc
, *g2
);
974 Printf(" [1] size=%zd '%s' %s\n", g1
->size
,
975 MaybeDemangleGlobalName(g1
->name
), g1_loc
.data());
976 Printf(" [2] size=%zd '%s' %s\n", g2
->size
,
977 MaybeDemangleGlobalName(g2
->name
), g2_loc
.data());
978 if (stack_id1
&& stack_id2
) {
979 Printf("These globals were registered at these points:\n");
981 StackDepotGet(stack_id1
).Print();
983 StackDepotGet(stack_id2
).Print();
985 Report("HINT: if you don't care about these errors you may set "
986 "ASAN_OPTIONS=detect_odr_violation=0\n");
987 InternalScopedString
error_msg(256);
988 error_msg
.append("odr-violation: global '%s' at %s",
989 MaybeDemangleGlobalName(g1
->name
), g1_loc
.data());
990 ReportErrorSummary(error_msg
.data());
993 // ----------------------- CheckForInvalidPointerPair ----------- {{{1
995 ReportInvalidPointerPair(uptr pc
, uptr bp
, uptr sp
, uptr a1
, uptr a2
) {
996 ScopedInErrorReport in_report
;
997 const char *bug_type
= "invalid-pointer-pair";
999 Printf("%s", d
.Warning());
1000 Report("ERROR: AddressSanitizer: invalid-pointer-pair: %p %p\n", a1
, a2
);
1001 Printf("%s", d
.EndWarning());
1002 GET_STACK_TRACE_FATAL(pc
, bp
);
1004 DescribeAddress(a1
, 1, bug_type
);
1005 DescribeAddress(a2
, 1, bug_type
);
1006 ReportErrorSummary(bug_type
, &stack
);
1009 static INLINE
void CheckForInvalidPointerPair(void *p1
, void *p2
) {
1010 if (!flags()->detect_invalid_pointer_pairs
) return;
1011 uptr a1
= reinterpret_cast<uptr
>(p1
);
1012 uptr a2
= reinterpret_cast<uptr
>(p2
);
1013 AsanChunkView chunk1
= FindHeapChunkByAddress(a1
);
1014 AsanChunkView chunk2
= FindHeapChunkByAddress(a2
);
1015 bool valid1
= chunk1
.IsAllocated();
1016 bool valid2
= chunk2
.IsAllocated();
1017 if (!valid1
|| !valid2
|| !chunk1
.Eq(chunk2
)) {
1018 GET_CALLER_PC_BP_SP
;
1019 return ReportInvalidPointerPair(pc
, bp
, sp
, a1
, a2
);
1022 // ----------------------- Mac-specific reports ----------------- {{{1
1024 void ReportMacMzReallocUnknown(uptr addr
, uptr zone_ptr
, const char *zone_name
,
1025 BufferedStackTrace
*stack
) {
1026 ScopedInErrorReport in_report
;
1027 Printf("mz_realloc(%p) -- attempting to realloc unallocated memory.\n"
1028 "This is an unrecoverable problem, exiting now.\n",
1030 PrintZoneForPointer(addr
, zone_ptr
, zone_name
);
1032 DescribeHeapAddress(addr
, 1);
1035 // -------------- SuppressErrorReport -------------- {{{1
1036 // Avoid error reports duplicating for ASan recover mode.
1037 static bool SuppressErrorReport(uptr pc
) {
1038 if (!common_flags()->suppress_equal_pcs
) return false;
1039 for (unsigned i
= 0; i
< kAsanBuggyPcPoolSize
; i
++) {
1040 uptr cmp
= atomic_load_relaxed(&AsanBuggyPcPool
[i
]);
1041 if (cmp
== 0 && atomic_compare_exchange_strong(&AsanBuggyPcPool
[i
], &cmp
,
1042 pc
, memory_order_relaxed
))
1044 if (cmp
== pc
) return true;
1049 static void PrintContainerOverflowHint() {
1050 Printf("HINT: if you don't care about these errors you may set "
1051 "ASAN_OPTIONS=detect_container_overflow=0.\n"
1052 "If you suspect a false positive see also: "
1053 "https://github.com/google/sanitizers/wiki/"
1054 "AddressSanitizerContainerOverflow.\n");
1057 static bool AdjacentShadowValuesAreFullyPoisoned(u8
*s
) {
1058 return s
[-1] > 127 && s
[1] > 127;
1061 void ReportGenericError(uptr pc
, uptr bp
, uptr sp
, uptr addr
, bool is_write
,
1062 uptr access_size
, u32 exp
, bool fatal
) {
1063 if (!fatal
&& SuppressErrorReport(pc
)) return;
1064 ENABLE_FRAME_POINTER
;
1068 if (access_size
<= 9) {
1069 char desr
[] = "?-byte";
1070 desr
[0] = '0' + access_size
;
1071 SS
.Scare(access_size
+ access_size
/ 2, desr
);
1072 } else if (access_size
>= 10) {
1073 SS
.Scare(15, "multi-byte");
1075 is_write
? SS
.Scare(20, "write") : SS
.Scare(1, "read");
1078 // Optimization experiments.
1079 // The experiments can be used to evaluate potential optimizations that remove
1080 // instrumentation (assess false negatives). Instead of completely removing
1081 // some instrumentation, compiler can emit special calls into runtime
1082 // (e.g. __asan_report_exp_load1 instead of __asan_report_load1) and pass
1083 // mask of experiments (exp).
1084 // The reaction to a non-zero value of exp is to be defined.
1087 // Determine the error type.
1088 const char *bug_descr
= "unknown-crash";
1090 if (AddrIsInMem(addr
)) {
1091 u8
*shadow_addr
= (u8
*)MemToShadow(addr
);
1092 // If we are accessing 16 bytes, look at the second shadow byte.
1093 if (*shadow_addr
== 0 && access_size
> SHADOW_GRANULARITY
)
1095 // If we are in the partial right redzone, look at the next shadow byte.
1096 if (*shadow_addr
> 0 && *shadow_addr
< 128)
1098 bool far_from_bounds
= false;
1099 shadow_val
= *shadow_addr
;
1100 int bug_type_score
= 0;
1101 // For use-after-frees reads are almost as bad as writes.
1102 int read_after_free_bonus
= 0;
1103 switch (shadow_val
) {
1104 case kAsanHeapLeftRedzoneMagic
:
1105 case kAsanHeapRightRedzoneMagic
:
1106 case kAsanArrayCookieMagic
:
1107 bug_descr
= "heap-buffer-overflow";
1108 bug_type_score
= 10;
1109 far_from_bounds
= AdjacentShadowValuesAreFullyPoisoned(shadow_addr
);
1111 case kAsanHeapFreeMagic
:
1112 bug_descr
= "heap-use-after-free";
1113 bug_type_score
= 20;
1114 if (!is_write
) read_after_free_bonus
= 18;
1116 case kAsanStackLeftRedzoneMagic
:
1117 bug_descr
= "stack-buffer-underflow";
1118 bug_type_score
= 25;
1119 far_from_bounds
= AdjacentShadowValuesAreFullyPoisoned(shadow_addr
);
1121 case kAsanInitializationOrderMagic
:
1122 bug_descr
= "initialization-order-fiasco";
1125 case kAsanStackMidRedzoneMagic
:
1126 case kAsanStackRightRedzoneMagic
:
1127 case kAsanStackPartialRedzoneMagic
:
1128 bug_descr
= "stack-buffer-overflow";
1129 bug_type_score
= 25;
1130 far_from_bounds
= AdjacentShadowValuesAreFullyPoisoned(shadow_addr
);
1132 case kAsanStackAfterReturnMagic
:
1133 bug_descr
= "stack-use-after-return";
1134 bug_type_score
= 30;
1135 if (!is_write
) read_after_free_bonus
= 18;
1137 case kAsanUserPoisonedMemoryMagic
:
1138 bug_descr
= "use-after-poison";
1139 bug_type_score
= 20;
1141 case kAsanContiguousContainerOOBMagic
:
1142 bug_descr
= "container-overflow";
1143 bug_type_score
= 10;
1145 case kAsanStackUseAfterScopeMagic
:
1146 bug_descr
= "stack-use-after-scope";
1147 bug_type_score
= 10;
1149 case kAsanGlobalRedzoneMagic
:
1150 bug_descr
= "global-buffer-overflow";
1151 bug_type_score
= 10;
1152 far_from_bounds
= AdjacentShadowValuesAreFullyPoisoned(shadow_addr
);
1154 case kAsanIntraObjectRedzone
:
1155 bug_descr
= "intra-object-overflow";
1156 bug_type_score
= 10;
1158 case kAsanAllocaLeftMagic
:
1159 case kAsanAllocaRightMagic
:
1160 bug_descr
= "dynamic-stack-buffer-overflow";
1161 bug_type_score
= 25;
1162 far_from_bounds
= AdjacentShadowValuesAreFullyPoisoned(shadow_addr
);
1165 SS
.Scare(bug_type_score
+ read_after_free_bonus
, bug_descr
);
1166 if (far_from_bounds
)
1167 SS
.Scare(10, "far-from-bounds");
1170 ReportData report
= { pc
, sp
, bp
, addr
, (bool)is_write
, access_size
,
1172 ScopedInErrorReport
in_report(&report
, fatal
);
1175 Printf("%s", d
.Warning());
1176 Report("ERROR: AddressSanitizer: %s on address "
1177 "%p at pc %p bp %p sp %p\n",
1178 bug_descr
, (void*)addr
, pc
, bp
, sp
);
1179 Printf("%s", d
.EndWarning());
1181 u32 curr_tid
= GetCurrentTidOrInvalid();
1183 Printf("%s%s of size %zu at %p thread T%d%s%s\n",
1185 access_size
? (is_write
? "WRITE" : "READ") : "ACCESS",
1186 access_size
, (void*)addr
, curr_tid
,
1187 ThreadNameWithParenthesis(curr_tid
, tname
, sizeof(tname
)),
1191 GET_STACK_TRACE_FATAL(pc
, bp
);
1194 DescribeAddress(addr
, access_size
, bug_descr
);
1195 if (shadow_val
== kAsanContiguousContainerOOBMagic
)
1196 PrintContainerOverflowHint();
1197 ReportErrorSummary(bug_descr
, &stack
);
1198 PrintShadowMemoryForAddress(addr
);
1201 } // namespace __asan
1203 // --------------------------- Interface --------------------- {{{1
1204 using namespace __asan
; // NOLINT
1206 void __asan_report_error(uptr pc
, uptr bp
, uptr sp
, uptr addr
, int is_write
,
1207 uptr access_size
, u32 exp
) {
1208 ENABLE_FRAME_POINTER
;
1209 bool fatal
= flags()->halt_on_error
;
1210 ReportGenericError(pc
, bp
, sp
, addr
, is_write
, access_size
, exp
, fatal
);
1213 void NOINLINE
__asan_set_error_report_callback(void (*callback
)(const char*)) {
1214 BlockingMutexLock
l(&error_message_buf_mutex
);
1215 error_report_callback
= callback
;
1218 void __asan_describe_address(uptr addr
) {
1219 // Thread registry must be locked while we're describing an address.
1220 asanThreadRegistry().Lock();
1221 DescribeAddress(addr
, 1, "");
1222 asanThreadRegistry().Unlock();
1225 int __asan_report_present() {
1226 return report_happened
? 1 : 0;
1229 uptr
__asan_get_report_pc() {
1230 return report_data
.pc
;
1233 uptr
__asan_get_report_bp() {
1234 return report_data
.bp
;
1237 uptr
__asan_get_report_sp() {
1238 return report_data
.sp
;
1241 uptr
__asan_get_report_address() {
1242 return report_data
.addr
;
1245 int __asan_get_report_access_type() {
1246 return report_data
.is_write
? 1 : 0;
1249 uptr
__asan_get_report_access_size() {
1250 return report_data
.access_size
;
1253 const char *__asan_get_report_description() {
1254 return report_data
.description
;
1258 SANITIZER_INTERFACE_ATTRIBUTE
1259 void __sanitizer_ptr_sub(void *a
, void *b
) {
1260 CheckForInvalidPointerPair(a
, b
);
1262 SANITIZER_INTERFACE_ATTRIBUTE
1263 void __sanitizer_ptr_cmp(void *a
, void *b
) {
1264 CheckForInvalidPointerPair(a
, b
);
1268 #if !SANITIZER_SUPPORTS_WEAK_HOOKS
1269 // Provide default implementation of __asan_on_error that does nothing
1270 // and may be overriden by user.
1271 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE
1272 void __asan_on_error() {}