1 //===-- asan_report.cpp ---------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file is a part of AddressSanitizer, an address sanity checker.
11 // This file contains error reporting code.
12 //===----------------------------------------------------------------------===//
14 #include "asan_report.h"
16 #include "asan_descriptions.h"
17 #include "asan_errors.h"
18 #include "asan_flags.h"
19 #include "asan_internal.h"
20 #include "asan_mapping.h"
21 #include "asan_scariness_score.h"
22 #include "asan_stack.h"
23 #include "asan_thread.h"
24 #include "sanitizer_common/sanitizer_common.h"
25 #include "sanitizer_common/sanitizer_flags.h"
26 #include "sanitizer_common/sanitizer_interface_internal.h"
27 #include "sanitizer_common/sanitizer_placement_new.h"
28 #include "sanitizer_common/sanitizer_report_decorator.h"
29 #include "sanitizer_common/sanitizer_stackdepot.h"
30 #include "sanitizer_common/sanitizer_symbolizer.h"
34 // -------------------- User-specified callbacks ----------------- {{{1
35 static void (*error_report_callback
)(const char*);
36 using ErrorMessageBuffer
= InternalMmapVectorNoCtor
<char, true>;
38 alignof(ErrorMessageBuffer
)) static char error_message_buffer_placeholder
39 [sizeof(ErrorMessageBuffer
)];
40 static ErrorMessageBuffer
*error_message_buffer
= nullptr;
41 static Mutex error_message_buf_mutex
;
42 static const unsigned kAsanBuggyPcPoolSize
= 25;
43 static __sanitizer::atomic_uintptr_t AsanBuggyPcPool
[kAsanBuggyPcPoolSize
];
45 void AppendToErrorMessageBuffer(const char *buffer
) {
46 Lock
l(&error_message_buf_mutex
);
47 if (!error_message_buffer
) {
48 error_message_buffer
=
49 new (error_message_buffer_placeholder
) ErrorMessageBuffer();
50 error_message_buffer
->Initialize(kErrorMessageBufferSize
);
52 uptr error_message_buffer_len
= error_message_buffer
->size();
53 uptr buffer_len
= internal_strlen(buffer
);
54 error_message_buffer
->resize(error_message_buffer_len
+ buffer_len
);
55 internal_memcpy(error_message_buffer
->data() + error_message_buffer_len
,
59 // ---------------------- Helper functions ----------------------- {{{1
61 void PrintMemoryByte(InternalScopedString
*str
, const char *before
, u8 byte
,
62 bool in_shadow
, const char *after
) {
64 str
->AppendF("%s%s%x%x%s%s", before
,
65 in_shadow
? d
.ShadowByte(byte
) : d
.MemoryByte(), byte
>> 4,
66 byte
& 15, d
.Default(), after
);
69 static void PrintZoneForPointer(uptr ptr
, uptr zone_ptr
,
70 const char *zone_name
) {
73 Printf("malloc_zone_from_ptr(%p) = %p, which is %s\n", (void *)ptr
,
74 (void *)zone_ptr
, zone_name
);
76 Printf("malloc_zone_from_ptr(%p) = %p, which doesn't have a name\n",
77 (void *)ptr
, (void *)zone_ptr
);
80 Printf("malloc_zone_from_ptr(%p) = 0\n", (void *)ptr
);
84 // ---------------------- Address Descriptions ------------------- {{{1
86 bool ParseFrameDescription(const char *frame_descr
,
87 InternalMmapVector
<StackVarDescr
> *vars
) {
90 // This string is created by the compiler and has the following form:
91 // "n alloc_1 alloc_2 ... alloc_n"
92 // where alloc_i looks like "offset size len ObjectName"
93 // or "offset size len ObjectName:line".
94 uptr n_objects
= (uptr
)internal_simple_strtoll(frame_descr
, &p
, 10);
98 for (uptr i
= 0; i
< n_objects
; i
++) {
99 uptr beg
= (uptr
)internal_simple_strtoll(p
, &p
, 10);
100 uptr size
= (uptr
)internal_simple_strtoll(p
, &p
, 10);
101 uptr len
= (uptr
)internal_simple_strtoll(p
, &p
, 10);
102 if (beg
== 0 || size
== 0 || *p
!= ' ') {
106 char *colon_pos
= internal_strchr(p
, ':');
109 if (colon_pos
!= nullptr && colon_pos
< p
+ len
) {
110 name_len
= colon_pos
- p
;
111 line
= (uptr
)internal_simple_strtoll(colon_pos
+ 1, nullptr, 10);
113 StackVarDescr var
= {beg
, size
, p
, name_len
, line
};
114 vars
->push_back(var
);
121 // -------------------- Different kinds of reports ----------------- {{{1
123 // Use ScopedInErrorReport to run common actions just before and
124 // immediately after printing error report.
125 class ScopedInErrorReport
{
127 explicit ScopedInErrorReport(bool fatal
= false)
128 : halt_on_error_(fatal
|| flags()->halt_on_error
) {
129 // Make sure the registry and sanitizer report mutexes are locked while
130 // we're printing an error report.
131 // We can lock them only here to avoid self-deadlock in case of
132 // recursive reports.
133 asanThreadRegistry().Lock();
135 "=================================================================\n");
138 ~ScopedInErrorReport() {
139 if (halt_on_error_
&& !__sanitizer_acquire_crash_state()) {
140 asanThreadRegistry().Unlock();
144 if (current_error_
.IsValid()) current_error_
.Print();
146 // Make sure the current thread is announced.
147 DescribeThread(GetCurrentThread());
148 // We may want to grab this lock again when printing stats.
149 asanThreadRegistry().Unlock();
150 // Print memory stats.
151 if (flags()->print_stats
)
152 __asan_print_accumulated_stats();
154 if (common_flags()->print_cmdline
)
157 if (common_flags()->print_module_map
== 2)
160 // Copy the message buffer so that we could start logging without holding a
161 // lock that gets acquired during printing.
162 InternalScopedString buffer_copy
;
164 Lock
l(&error_message_buf_mutex
);
165 error_message_buffer
->push_back('\0');
166 buffer_copy
.Append(error_message_buffer
->data());
167 // Clear error_message_buffer so that if we find other errors
168 // we don't re-log this error.
169 error_message_buffer
->clear();
172 LogFullErrorReport(buffer_copy
.data());
174 if (error_report_callback
) {
175 error_report_callback(buffer_copy
.data());
178 if (halt_on_error_
&& common_flags()->abort_on_error
) {
179 // On Android the message is truncated to 512 characters.
180 // FIXME: implement "compact" error format, possibly without, or with
181 // highly compressed stack traces?
182 // FIXME: or just use the summary line as abort message?
183 SetAbortMessage(buffer_copy
.data());
186 // In halt_on_error = false mode, reset the current error object (before
189 internal_memset(¤t_error_
, 0, sizeof(current_error_
));
191 if (halt_on_error_
) {
192 Report("ABORTING\n");
197 void ReportError(const ErrorDescription
&description
) {
198 // Can only report one error per ScopedInErrorReport.
199 CHECK_EQ(current_error_
.kind
, kErrorKindInvalid
);
200 internal_memcpy(¤t_error_
, &description
, sizeof(current_error_
));
203 static ErrorDescription
&CurrentError() {
204 return current_error_
;
208 ScopedErrorReportLock error_report_lock_
;
209 // Error currently being reported. This enables the destructor to interact
210 // with the debugger and point it to an error description.
211 static ErrorDescription current_error_
;
215 ErrorDescription
ScopedInErrorReport::current_error_(LINKER_INITIALIZED
);
217 void ReportDeadlySignal(const SignalContext
&sig
) {
218 ScopedInErrorReport
in_report(/*fatal*/ true);
219 ErrorDeadlySignal
error(GetCurrentTidOrInvalid(), sig
);
220 in_report
.ReportError(error
);
223 void ReportDoubleFree(uptr addr
, BufferedStackTrace
*free_stack
) {
224 ScopedInErrorReport in_report
;
225 ErrorDoubleFree
error(GetCurrentTidOrInvalid(), free_stack
, addr
);
226 in_report
.ReportError(error
);
229 void ReportNewDeleteTypeMismatch(uptr addr
, uptr delete_size
,
230 uptr delete_alignment
,
231 BufferedStackTrace
*free_stack
) {
232 ScopedInErrorReport in_report
;
233 ErrorNewDeleteTypeMismatch
error(GetCurrentTidOrInvalid(), free_stack
, addr
,
234 delete_size
, delete_alignment
);
235 in_report
.ReportError(error
);
238 void ReportFreeNotMalloced(uptr addr
, BufferedStackTrace
*free_stack
) {
239 ScopedInErrorReport in_report
;
240 ErrorFreeNotMalloced
error(GetCurrentTidOrInvalid(), free_stack
, addr
);
241 in_report
.ReportError(error
);
244 void ReportAllocTypeMismatch(uptr addr
, BufferedStackTrace
*free_stack
,
245 AllocType alloc_type
,
246 AllocType dealloc_type
) {
247 ScopedInErrorReport in_report
;
248 ErrorAllocTypeMismatch
error(GetCurrentTidOrInvalid(), free_stack
, addr
,
249 alloc_type
, dealloc_type
);
250 in_report
.ReportError(error
);
253 void ReportMallocUsableSizeNotOwned(uptr addr
, BufferedStackTrace
*stack
) {
254 ScopedInErrorReport in_report
;
255 ErrorMallocUsableSizeNotOwned
error(GetCurrentTidOrInvalid(), stack
, addr
);
256 in_report
.ReportError(error
);
259 void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr
,
260 BufferedStackTrace
*stack
) {
261 ScopedInErrorReport in_report
;
262 ErrorSanitizerGetAllocatedSizeNotOwned
error(GetCurrentTidOrInvalid(), stack
,
264 in_report
.ReportError(error
);
267 void ReportCallocOverflow(uptr count
, uptr size
, BufferedStackTrace
*stack
) {
268 ScopedInErrorReport
in_report(/*fatal*/ true);
269 ErrorCallocOverflow
error(GetCurrentTidOrInvalid(), stack
, count
, size
);
270 in_report
.ReportError(error
);
273 void ReportReallocArrayOverflow(uptr count
, uptr size
,
274 BufferedStackTrace
*stack
) {
275 ScopedInErrorReport
in_report(/*fatal*/ true);
276 ErrorReallocArrayOverflow
error(GetCurrentTidOrInvalid(), stack
, count
, size
);
277 in_report
.ReportError(error
);
280 void ReportPvallocOverflow(uptr size
, BufferedStackTrace
*stack
) {
281 ScopedInErrorReport
in_report(/*fatal*/ true);
282 ErrorPvallocOverflow
error(GetCurrentTidOrInvalid(), stack
, size
);
283 in_report
.ReportError(error
);
286 void ReportInvalidAllocationAlignment(uptr alignment
,
287 BufferedStackTrace
*stack
) {
288 ScopedInErrorReport
in_report(/*fatal*/ true);
289 ErrorInvalidAllocationAlignment
error(GetCurrentTidOrInvalid(), stack
,
291 in_report
.ReportError(error
);
294 void ReportInvalidAlignedAllocAlignment(uptr size
, uptr alignment
,
295 BufferedStackTrace
*stack
) {
296 ScopedInErrorReport
in_report(/*fatal*/ true);
297 ErrorInvalidAlignedAllocAlignment
error(GetCurrentTidOrInvalid(), stack
,
299 in_report
.ReportError(error
);
302 void ReportInvalidPosixMemalignAlignment(uptr alignment
,
303 BufferedStackTrace
*stack
) {
304 ScopedInErrorReport
in_report(/*fatal*/ true);
305 ErrorInvalidPosixMemalignAlignment
error(GetCurrentTidOrInvalid(), stack
,
307 in_report
.ReportError(error
);
310 void ReportAllocationSizeTooBig(uptr user_size
, uptr total_size
, uptr max_size
,
311 BufferedStackTrace
*stack
) {
312 ScopedInErrorReport
in_report(/*fatal*/ true);
313 ErrorAllocationSizeTooBig
error(GetCurrentTidOrInvalid(), stack
, user_size
,
314 total_size
, max_size
);
315 in_report
.ReportError(error
);
318 void ReportRssLimitExceeded(BufferedStackTrace
*stack
) {
319 ScopedInErrorReport
in_report(/*fatal*/ true);
320 ErrorRssLimitExceeded
error(GetCurrentTidOrInvalid(), stack
);
321 in_report
.ReportError(error
);
324 void ReportOutOfMemory(uptr requested_size
, BufferedStackTrace
*stack
) {
325 ScopedInErrorReport
in_report(/*fatal*/ true);
326 ErrorOutOfMemory
error(GetCurrentTidOrInvalid(), stack
, requested_size
);
327 in_report
.ReportError(error
);
330 void ReportStringFunctionMemoryRangesOverlap(const char *function
,
331 const char *offset1
, uptr length1
,
332 const char *offset2
, uptr length2
,
333 BufferedStackTrace
*stack
) {
334 ScopedInErrorReport in_report
;
335 ErrorStringFunctionMemoryRangesOverlap
error(
336 GetCurrentTidOrInvalid(), stack
, (uptr
)offset1
, length1
, (uptr
)offset2
,
338 in_report
.ReportError(error
);
341 void ReportStringFunctionSizeOverflow(uptr offset
, uptr size
,
342 BufferedStackTrace
*stack
) {
343 ScopedInErrorReport in_report
;
344 ErrorStringFunctionSizeOverflow
error(GetCurrentTidOrInvalid(), stack
, offset
,
346 in_report
.ReportError(error
);
349 void ReportBadParamsToAnnotateContiguousContainer(uptr beg
, uptr end
,
350 uptr old_mid
, uptr new_mid
,
351 BufferedStackTrace
*stack
) {
352 ScopedInErrorReport in_report
;
353 ErrorBadParamsToAnnotateContiguousContainer
error(
354 GetCurrentTidOrInvalid(), stack
, beg
, end
, old_mid
, new_mid
);
355 in_report
.ReportError(error
);
358 void ReportBadParamsToAnnotateDoubleEndedContiguousContainer(
359 uptr storage_beg
, uptr storage_end
, uptr old_container_beg
,
360 uptr old_container_end
, uptr new_container_beg
, uptr new_container_end
,
361 BufferedStackTrace
*stack
) {
362 ScopedInErrorReport in_report
;
363 ErrorBadParamsToAnnotateDoubleEndedContiguousContainer
error(
364 GetCurrentTidOrInvalid(), stack
, storage_beg
, storage_end
,
365 old_container_beg
, old_container_end
, new_container_beg
,
367 in_report
.ReportError(error
);
370 void ReportBadParamsToCopyContiguousContainerAnnotations(
371 uptr old_storage_beg
, uptr old_storage_end
, uptr new_storage_beg
,
372 uptr new_storage_end
, BufferedStackTrace
*stack
) {
373 ScopedInErrorReport in_report
;
374 ErrorBadParamsToCopyContiguousContainerAnnotations
error(
375 GetCurrentTidOrInvalid(), stack
, old_storage_beg
, old_storage_end
,
376 new_storage_beg
, new_storage_end
);
377 in_report
.ReportError(error
);
380 void ReportODRViolation(const __asan_global
*g1
, u32 stack_id1
,
381 const __asan_global
*g2
, u32 stack_id2
) {
382 ScopedInErrorReport in_report
;
383 ErrorODRViolation
error(GetCurrentTidOrInvalid(), g1
, stack_id1
, g2
,
385 in_report
.ReportError(error
);
388 // ----------------------- CheckForInvalidPointerPair ----------- {{{1
389 static NOINLINE
void ReportInvalidPointerPair(uptr pc
, uptr bp
, uptr sp
,
391 ScopedInErrorReport in_report
;
392 ErrorInvalidPointerPair
error(GetCurrentTidOrInvalid(), pc
, bp
, sp
, a1
, a2
);
393 in_report
.ReportError(error
);
396 static bool IsInvalidPointerPair(uptr a1
, uptr a2
) {
400 // 256B in shadow memory can be iterated quite fast
401 static const uptr kMaxOffset
= 2048;
403 uptr left
= a1
< a2
? a1
: a2
;
404 uptr right
= a1
< a2
? a2
: a1
;
405 uptr offset
= right
- left
;
406 if (offset
<= kMaxOffset
)
407 return __asan_region_is_poisoned(left
, offset
);
409 AsanThread
*t
= GetCurrentThread();
411 // check whether left is a stack memory pointer
412 if (uptr shadow_offset1
= t
->GetStackVariableShadowStart(left
)) {
413 uptr shadow_offset2
= t
->GetStackVariableShadowStart(right
);
414 return shadow_offset2
== 0 || shadow_offset1
!= shadow_offset2
;
417 // check whether left is a heap memory address
418 HeapAddressDescription hdesc1
, hdesc2
;
419 if (GetHeapAddressInformation(left
, 0, &hdesc1
) &&
420 hdesc1
.chunk_access
.access_type
== kAccessTypeInside
)
421 return !GetHeapAddressInformation(right
, 0, &hdesc2
) ||
422 hdesc2
.chunk_access
.access_type
!= kAccessTypeInside
||
423 hdesc1
.chunk_access
.chunk_begin
!= hdesc2
.chunk_access
.chunk_begin
;
425 // check whether left is an address of a global variable
426 GlobalAddressDescription gdesc1
, gdesc2
;
427 if (GetGlobalAddressInformation(left
, 0, &gdesc1
))
428 return !GetGlobalAddressInformation(right
- 1, 0, &gdesc2
) ||
429 !gdesc1
.PointsInsideTheSameVariable(gdesc2
);
431 if (t
->GetStackVariableShadowStart(right
) ||
432 GetHeapAddressInformation(right
, 0, &hdesc2
) ||
433 GetGlobalAddressInformation(right
- 1, 0, &gdesc2
))
436 // At this point we know nothing about both a1 and a2 addresses.
440 static inline void CheckForInvalidPointerPair(void *p1
, void *p2
) {
441 switch (flags()->detect_invalid_pointer_pairs
) {
445 if (p1
== nullptr || p2
== nullptr)
450 uptr a1
= reinterpret_cast<uptr
>(p1
);
451 uptr a2
= reinterpret_cast<uptr
>(p2
);
453 if (IsInvalidPointerPair(a1
, a2
)) {
455 ReportInvalidPointerPair(pc
, bp
, sp
, a1
, a2
);
458 // ----------------------- Mac-specific reports ----------------- {{{1
460 void ReportMacMzReallocUnknown(uptr addr
, uptr zone_ptr
, const char *zone_name
,
461 BufferedStackTrace
*stack
) {
462 ScopedInErrorReport in_report
;
464 "mz_realloc(%p) -- attempting to realloc unallocated memory.\n"
465 "This is an unrecoverable problem, exiting now.\n",
467 PrintZoneForPointer(addr
, zone_ptr
, zone_name
);
469 DescribeAddressIfHeap(addr
);
472 // -------------- SuppressErrorReport -------------- {{{1
473 // Avoid error reports duplicating for ASan recover mode.
474 static bool SuppressErrorReport(uptr pc
) {
475 if (!common_flags()->suppress_equal_pcs
) return false;
476 for (unsigned i
= 0; i
< kAsanBuggyPcPoolSize
; i
++) {
477 uptr cmp
= atomic_load_relaxed(&AsanBuggyPcPool
[i
]);
478 if (cmp
== 0 && atomic_compare_exchange_strong(&AsanBuggyPcPool
[i
], &cmp
,
479 pc
, memory_order_relaxed
))
481 if (cmp
== pc
) return true;
486 void ReportGenericError(uptr pc
, uptr bp
, uptr sp
, uptr addr
, bool is_write
,
487 uptr access_size
, u32 exp
, bool fatal
) {
488 if (__asan_test_only_reported_buggy_pointer
) {
489 *__asan_test_only_reported_buggy_pointer
= addr
;
492 if (!fatal
&& SuppressErrorReport(pc
)) return;
493 ENABLE_FRAME_POINTER
;
495 // Optimization experiments.
496 // The experiments can be used to evaluate potential optimizations that remove
497 // instrumentation (assess false negatives). Instead of completely removing
498 // some instrumentation, compiler can emit special calls into runtime
499 // (e.g. __asan_report_exp_load1 instead of __asan_report_load1) and pass
500 // mask of experiments (exp).
501 // The reaction to a non-zero value of exp is to be defined.
504 ScopedInErrorReport
in_report(fatal
);
505 ErrorGeneric
error(GetCurrentTidOrInvalid(), pc
, bp
, sp
, addr
, is_write
,
507 in_report
.ReportError(error
);
510 } // namespace __asan
512 // --------------------------- Interface --------------------- {{{1
513 using namespace __asan
;
515 void __asan_report_error(uptr pc
, uptr bp
, uptr sp
, uptr addr
, int is_write
,
516 uptr access_size
, u32 exp
) {
517 ENABLE_FRAME_POINTER
;
518 bool fatal
= flags()->halt_on_error
;
519 ReportGenericError(pc
, bp
, sp
, addr
, is_write
, access_size
, exp
, fatal
);
522 void NOINLINE
__asan_set_error_report_callback(void (*callback
)(const char*)) {
523 Lock
l(&error_message_buf_mutex
);
524 error_report_callback
= callback
;
527 void __asan_describe_address(uptr addr
) {
528 // Thread registry must be locked while we're describing an address.
529 asanThreadRegistry().Lock();
530 PrintAddressDescription(addr
, 1, "");
531 asanThreadRegistry().Unlock();
534 int __asan_report_present() {
535 return ScopedInErrorReport::CurrentError().kind
!= kErrorKindInvalid
;
538 uptr
__asan_get_report_pc() {
539 if (ScopedInErrorReport::CurrentError().kind
== kErrorKindGeneric
)
540 return ScopedInErrorReport::CurrentError().Generic
.pc
;
544 uptr
__asan_get_report_bp() {
545 if (ScopedInErrorReport::CurrentError().kind
== kErrorKindGeneric
)
546 return ScopedInErrorReport::CurrentError().Generic
.bp
;
550 uptr
__asan_get_report_sp() {
551 if (ScopedInErrorReport::CurrentError().kind
== kErrorKindGeneric
)
552 return ScopedInErrorReport::CurrentError().Generic
.sp
;
556 uptr
__asan_get_report_address() {
557 ErrorDescription
&err
= ScopedInErrorReport::CurrentError();
558 if (err
.kind
== kErrorKindGeneric
)
559 return err
.Generic
.addr_description
.Address();
560 else if (err
.kind
== kErrorKindDoubleFree
)
561 return err
.DoubleFree
.addr_description
.addr
;
565 int __asan_get_report_access_type() {
566 if (ScopedInErrorReport::CurrentError().kind
== kErrorKindGeneric
)
567 return ScopedInErrorReport::CurrentError().Generic
.is_write
;
571 uptr
__asan_get_report_access_size() {
572 if (ScopedInErrorReport::CurrentError().kind
== kErrorKindGeneric
)
573 return ScopedInErrorReport::CurrentError().Generic
.access_size
;
577 const char *__asan_get_report_description() {
578 if (ScopedInErrorReport::CurrentError().kind
== kErrorKindGeneric
)
579 return ScopedInErrorReport::CurrentError().Generic
.bug_descr
;
580 return ScopedInErrorReport::CurrentError().Base
.scariness
.GetDescription();
584 SANITIZER_INTERFACE_ATTRIBUTE
585 void __sanitizer_ptr_sub(void *a
, void *b
) {
586 CheckForInvalidPointerPair(a
, b
);
588 SANITIZER_INTERFACE_ATTRIBUTE
589 void __sanitizer_ptr_cmp(void *a
, void *b
) {
590 CheckForInvalidPointerPair(a
, b
);
594 // Provide default implementation of __asan_on_error that does nothing
595 // and may be overriden by user.
596 SANITIZER_INTERFACE_WEAK_DEF(void, __asan_on_error
, void) {}