168d75effSDimitry Andric //===-- asan_report.cpp ---------------------------------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // This file is a part of AddressSanitizer, an address sanity checker.
1068d75effSDimitry Andric //
1168d75effSDimitry Andric // This file contains error reporting code.
1268d75effSDimitry Andric //===----------------------------------------------------------------------===//
1368d75effSDimitry Andric
1481ad6265SDimitry Andric #include "asan_report.h"
1581ad6265SDimitry Andric
1681ad6265SDimitry Andric #include "asan_descriptions.h"
1768d75effSDimitry Andric #include "asan_errors.h"
1868d75effSDimitry Andric #include "asan_flags.h"
1968d75effSDimitry Andric #include "asan_internal.h"
2068d75effSDimitry Andric #include "asan_mapping.h"
2168d75effSDimitry Andric #include "asan_scariness_score.h"
2268d75effSDimitry Andric #include "asan_stack.h"
2368d75effSDimitry Andric #include "asan_thread.h"
2468d75effSDimitry Andric #include "sanitizer_common/sanitizer_common.h"
2568d75effSDimitry Andric #include "sanitizer_common/sanitizer_flags.h"
2681ad6265SDimitry Andric #include "sanitizer_common/sanitizer_interface_internal.h"
27*0fca6ea1SDimitry Andric #include "sanitizer_common/sanitizer_placement_new.h"
2868d75effSDimitry Andric #include "sanitizer_common/sanitizer_report_decorator.h"
2968d75effSDimitry Andric #include "sanitizer_common/sanitizer_stackdepot.h"
3068d75effSDimitry Andric #include "sanitizer_common/sanitizer_symbolizer.h"
3168d75effSDimitry Andric
3268d75effSDimitry Andric namespace __asan {
3368d75effSDimitry Andric
3468d75effSDimitry Andric // -------------------- User-specified callbacks ----------------- {{{1
3568d75effSDimitry Andric static void (*error_report_callback)(const char*);
36*0fca6ea1SDimitry Andric using ErrorMessageBuffer = InternalMmapVectorNoCtor<char, true>;
37*0fca6ea1SDimitry Andric alignas(
38*0fca6ea1SDimitry Andric alignof(ErrorMessageBuffer)) static char error_message_buffer_placeholder
39*0fca6ea1SDimitry Andric [sizeof(ErrorMessageBuffer)];
40*0fca6ea1SDimitry Andric static ErrorMessageBuffer *error_message_buffer = nullptr;
41349cc55cSDimitry Andric static Mutex error_message_buf_mutex;
4268d75effSDimitry Andric static const unsigned kAsanBuggyPcPoolSize = 25;
4368d75effSDimitry Andric static __sanitizer::atomic_uintptr_t AsanBuggyPcPool[kAsanBuggyPcPoolSize];
4468d75effSDimitry Andric
AppendToErrorMessageBuffer(const char * buffer)4568d75effSDimitry Andric void AppendToErrorMessageBuffer(const char *buffer) {
46349cc55cSDimitry Andric Lock l(&error_message_buf_mutex);
4768d75effSDimitry Andric if (!error_message_buffer) {
4868d75effSDimitry Andric error_message_buffer =
49*0fca6ea1SDimitry Andric new (error_message_buffer_placeholder) ErrorMessageBuffer();
50*0fca6ea1SDimitry Andric error_message_buffer->Initialize(kErrorMessageBufferSize);
5168d75effSDimitry Andric }
52*0fca6ea1SDimitry Andric uptr error_message_buffer_len = error_message_buffer->size();
53*0fca6ea1SDimitry Andric uptr buffer_len = internal_strlen(buffer);
54*0fca6ea1SDimitry Andric error_message_buffer->resize(error_message_buffer_len + buffer_len);
55*0fca6ea1SDimitry Andric internal_memcpy(error_message_buffer->data() + error_message_buffer_len,
56*0fca6ea1SDimitry Andric buffer, buffer_len);
5768d75effSDimitry Andric }
5868d75effSDimitry Andric
5968d75effSDimitry Andric // ---------------------- Helper functions ----------------------- {{{1
6068d75effSDimitry Andric
PrintMemoryByte(InternalScopedString * str,const char * before,u8 byte,bool in_shadow,const char * after)6168d75effSDimitry Andric void PrintMemoryByte(InternalScopedString *str, const char *before, u8 byte,
6268d75effSDimitry Andric bool in_shadow, const char *after) {
6368d75effSDimitry Andric Decorator d;
645f757f3fSDimitry Andric str->AppendF("%s%s%x%x%s%s", before,
6568d75effSDimitry Andric in_shadow ? d.ShadowByte(byte) : d.MemoryByte(), byte >> 4,
6668d75effSDimitry Andric byte & 15, d.Default(), after);
6768d75effSDimitry Andric }
6868d75effSDimitry Andric
PrintZoneForPointer(uptr ptr,uptr zone_ptr,const char * zone_name)6968d75effSDimitry Andric static void PrintZoneForPointer(uptr ptr, uptr zone_ptr,
7068d75effSDimitry Andric const char *zone_name) {
7168d75effSDimitry Andric if (zone_ptr) {
7268d75effSDimitry Andric if (zone_name) {
73349cc55cSDimitry Andric Printf("malloc_zone_from_ptr(%p) = %p, which is %s\n", (void *)ptr,
74349cc55cSDimitry Andric (void *)zone_ptr, zone_name);
7568d75effSDimitry Andric } else {
7668d75effSDimitry Andric Printf("malloc_zone_from_ptr(%p) = %p, which doesn't have a name\n",
77349cc55cSDimitry Andric (void *)ptr, (void *)zone_ptr);
7868d75effSDimitry Andric }
7968d75effSDimitry Andric } else {
80349cc55cSDimitry Andric Printf("malloc_zone_from_ptr(%p) = 0\n", (void *)ptr);
8168d75effSDimitry Andric }
8268d75effSDimitry Andric }
8368d75effSDimitry Andric
8468d75effSDimitry Andric // ---------------------- Address Descriptions ------------------- {{{1
8568d75effSDimitry Andric
ParseFrameDescription(const char * frame_descr,InternalMmapVector<StackVarDescr> * vars)8668d75effSDimitry Andric bool ParseFrameDescription(const char *frame_descr,
8768d75effSDimitry Andric InternalMmapVector<StackVarDescr> *vars) {
8868d75effSDimitry Andric CHECK(frame_descr);
8968d75effSDimitry Andric const char *p;
9068d75effSDimitry Andric // This string is created by the compiler and has the following form:
9168d75effSDimitry Andric // "n alloc_1 alloc_2 ... alloc_n"
9268d75effSDimitry Andric // where alloc_i looks like "offset size len ObjectName"
9368d75effSDimitry Andric // or "offset size len ObjectName:line".
9468d75effSDimitry Andric uptr n_objects = (uptr)internal_simple_strtoll(frame_descr, &p, 10);
9568d75effSDimitry Andric if (n_objects == 0)
9668d75effSDimitry Andric return false;
9768d75effSDimitry Andric
9868d75effSDimitry Andric for (uptr i = 0; i < n_objects; i++) {
9968d75effSDimitry Andric uptr beg = (uptr)internal_simple_strtoll(p, &p, 10);
10068d75effSDimitry Andric uptr size = (uptr)internal_simple_strtoll(p, &p, 10);
10168d75effSDimitry Andric uptr len = (uptr)internal_simple_strtoll(p, &p, 10);
10268d75effSDimitry Andric if (beg == 0 || size == 0 || *p != ' ') {
10368d75effSDimitry Andric return false;
10468d75effSDimitry Andric }
10568d75effSDimitry Andric p++;
10668d75effSDimitry Andric char *colon_pos = internal_strchr(p, ':');
10768d75effSDimitry Andric uptr line = 0;
10868d75effSDimitry Andric uptr name_len = len;
10968d75effSDimitry Andric if (colon_pos != nullptr && colon_pos < p + len) {
11068d75effSDimitry Andric name_len = colon_pos - p;
11168d75effSDimitry Andric line = (uptr)internal_simple_strtoll(colon_pos + 1, nullptr, 10);
11268d75effSDimitry Andric }
11368d75effSDimitry Andric StackVarDescr var = {beg, size, p, name_len, line};
11468d75effSDimitry Andric vars->push_back(var);
11568d75effSDimitry Andric p += len;
11668d75effSDimitry Andric }
11768d75effSDimitry Andric
11868d75effSDimitry Andric return true;
11968d75effSDimitry Andric }
12068d75effSDimitry Andric
12168d75effSDimitry Andric // -------------------- Different kinds of reports ----------------- {{{1
12268d75effSDimitry Andric
12368d75effSDimitry Andric // Use ScopedInErrorReport to run common actions just before and
12468d75effSDimitry Andric // immediately after printing error report.
12568d75effSDimitry Andric class ScopedInErrorReport {
12668d75effSDimitry Andric public:
ScopedInErrorReport(bool fatal=false)12768d75effSDimitry Andric explicit ScopedInErrorReport(bool fatal = false)
12868d75effSDimitry Andric : halt_on_error_(fatal || flags()->halt_on_error) {
12968d75effSDimitry Andric // Make sure the registry and sanitizer report mutexes are locked while
13068d75effSDimitry Andric // we're printing an error report.
13168d75effSDimitry Andric // We can lock them only here to avoid self-deadlock in case of
13268d75effSDimitry Andric // recursive reports.
13368d75effSDimitry Andric asanThreadRegistry().Lock();
13468d75effSDimitry Andric Printf(
13568d75effSDimitry Andric "=================================================================\n");
13668d75effSDimitry Andric }
13768d75effSDimitry Andric
~ScopedInErrorReport()13868d75effSDimitry Andric ~ScopedInErrorReport() {
13968d75effSDimitry Andric if (halt_on_error_ && !__sanitizer_acquire_crash_state()) {
14068d75effSDimitry Andric asanThreadRegistry().Unlock();
14168d75effSDimitry Andric return;
14268d75effSDimitry Andric }
14368d75effSDimitry Andric ASAN_ON_ERROR();
14468d75effSDimitry Andric if (current_error_.IsValid()) current_error_.Print();
14568d75effSDimitry Andric
14668d75effSDimitry Andric // Make sure the current thread is announced.
14768d75effSDimitry Andric DescribeThread(GetCurrentThread());
14868d75effSDimitry Andric // We may want to grab this lock again when printing stats.
14968d75effSDimitry Andric asanThreadRegistry().Unlock();
15068d75effSDimitry Andric // Print memory stats.
15168d75effSDimitry Andric if (flags()->print_stats)
15268d75effSDimitry Andric __asan_print_accumulated_stats();
15368d75effSDimitry Andric
15468d75effSDimitry Andric if (common_flags()->print_cmdline)
15568d75effSDimitry Andric PrintCmdline();
15668d75effSDimitry Andric
157e8d8bef9SDimitry Andric if (common_flags()->print_module_map == 2)
158e8d8bef9SDimitry Andric DumpProcessMap();
15968d75effSDimitry Andric
16068d75effSDimitry Andric // Copy the message buffer so that we could start logging without holding a
161349cc55cSDimitry Andric // lock that gets acquired during printing.
162*0fca6ea1SDimitry Andric InternalScopedString buffer_copy;
16368d75effSDimitry Andric {
164349cc55cSDimitry Andric Lock l(&error_message_buf_mutex);
165*0fca6ea1SDimitry Andric error_message_buffer->push_back('\0');
166*0fca6ea1SDimitry Andric buffer_copy.Append(error_message_buffer->data());
1675ffd83dbSDimitry Andric // Clear error_message_buffer so that if we find other errors
1685ffd83dbSDimitry Andric // we don't re-log this error.
169*0fca6ea1SDimitry Andric error_message_buffer->clear();
17068d75effSDimitry Andric }
17168d75effSDimitry Andric
17268d75effSDimitry Andric LogFullErrorReport(buffer_copy.data());
17368d75effSDimitry Andric
17468d75effSDimitry Andric if (error_report_callback) {
17568d75effSDimitry Andric error_report_callback(buffer_copy.data());
17668d75effSDimitry Andric }
17768d75effSDimitry Andric
17868d75effSDimitry Andric if (halt_on_error_ && common_flags()->abort_on_error) {
17968d75effSDimitry Andric // On Android the message is truncated to 512 characters.
18068d75effSDimitry Andric // FIXME: implement "compact" error format, possibly without, or with
18168d75effSDimitry Andric // highly compressed stack traces?
18268d75effSDimitry Andric // FIXME: or just use the summary line as abort message?
18368d75effSDimitry Andric SetAbortMessage(buffer_copy.data());
18468d75effSDimitry Andric }
18568d75effSDimitry Andric
18668d75effSDimitry Andric // In halt_on_error = false mode, reset the current error object (before
18768d75effSDimitry Andric // unlocking).
18868d75effSDimitry Andric if (!halt_on_error_)
18968d75effSDimitry Andric internal_memset(¤t_error_, 0, sizeof(current_error_));
19068d75effSDimitry Andric
19168d75effSDimitry Andric if (halt_on_error_) {
19268d75effSDimitry Andric Report("ABORTING\n");
19368d75effSDimitry Andric Die();
19468d75effSDimitry Andric }
19568d75effSDimitry Andric }
19668d75effSDimitry Andric
ReportError(const ErrorDescription & description)19768d75effSDimitry Andric void ReportError(const ErrorDescription &description) {
19868d75effSDimitry Andric // Can only report one error per ScopedInErrorReport.
19968d75effSDimitry Andric CHECK_EQ(current_error_.kind, kErrorKindInvalid);
20068d75effSDimitry Andric internal_memcpy(¤t_error_, &description, sizeof(current_error_));
20168d75effSDimitry Andric }
20268d75effSDimitry Andric
CurrentError()20368d75effSDimitry Andric static ErrorDescription &CurrentError() {
20468d75effSDimitry Andric return current_error_;
20568d75effSDimitry Andric }
20668d75effSDimitry Andric
20768d75effSDimitry Andric private:
20868d75effSDimitry Andric ScopedErrorReportLock error_report_lock_;
20968d75effSDimitry Andric // Error currently being reported. This enables the destructor to interact
21068d75effSDimitry Andric // with the debugger and point it to an error description.
21168d75effSDimitry Andric static ErrorDescription current_error_;
21268d75effSDimitry Andric bool halt_on_error_;
21368d75effSDimitry Andric };
21468d75effSDimitry Andric
21568d75effSDimitry Andric ErrorDescription ScopedInErrorReport::current_error_(LINKER_INITIALIZED);
21668d75effSDimitry Andric
ReportDeadlySignal(const SignalContext & sig)21768d75effSDimitry Andric void ReportDeadlySignal(const SignalContext &sig) {
21868d75effSDimitry Andric ScopedInErrorReport in_report(/*fatal*/ true);
21968d75effSDimitry Andric ErrorDeadlySignal error(GetCurrentTidOrInvalid(), sig);
22068d75effSDimitry Andric in_report.ReportError(error);
22168d75effSDimitry Andric }
22268d75effSDimitry Andric
ReportDoubleFree(uptr addr,BufferedStackTrace * free_stack)22368d75effSDimitry Andric void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack) {
22468d75effSDimitry Andric ScopedInErrorReport in_report;
22568d75effSDimitry Andric ErrorDoubleFree error(GetCurrentTidOrInvalid(), free_stack, addr);
22668d75effSDimitry Andric in_report.ReportError(error);
22768d75effSDimitry Andric }
22868d75effSDimitry Andric
ReportNewDeleteTypeMismatch(uptr addr,uptr delete_size,uptr delete_alignment,BufferedStackTrace * free_stack)22968d75effSDimitry Andric void ReportNewDeleteTypeMismatch(uptr addr, uptr delete_size,
23068d75effSDimitry Andric uptr delete_alignment,
23168d75effSDimitry Andric BufferedStackTrace *free_stack) {
23268d75effSDimitry Andric ScopedInErrorReport in_report;
23368d75effSDimitry Andric ErrorNewDeleteTypeMismatch error(GetCurrentTidOrInvalid(), free_stack, addr,
23468d75effSDimitry Andric delete_size, delete_alignment);
23568d75effSDimitry Andric in_report.ReportError(error);
23668d75effSDimitry Andric }
23768d75effSDimitry Andric
ReportFreeNotMalloced(uptr addr,BufferedStackTrace * free_stack)23868d75effSDimitry Andric void ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack) {
23968d75effSDimitry Andric ScopedInErrorReport in_report;
24068d75effSDimitry Andric ErrorFreeNotMalloced error(GetCurrentTidOrInvalid(), free_stack, addr);
24168d75effSDimitry Andric in_report.ReportError(error);
24268d75effSDimitry Andric }
24368d75effSDimitry Andric
ReportAllocTypeMismatch(uptr addr,BufferedStackTrace * free_stack,AllocType alloc_type,AllocType dealloc_type)24468d75effSDimitry Andric void ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack,
24568d75effSDimitry Andric AllocType alloc_type,
24668d75effSDimitry Andric AllocType dealloc_type) {
24768d75effSDimitry Andric ScopedInErrorReport in_report;
24868d75effSDimitry Andric ErrorAllocTypeMismatch error(GetCurrentTidOrInvalid(), free_stack, addr,
24968d75effSDimitry Andric alloc_type, dealloc_type);
25068d75effSDimitry Andric in_report.ReportError(error);
25168d75effSDimitry Andric }
25268d75effSDimitry Andric
ReportMallocUsableSizeNotOwned(uptr addr,BufferedStackTrace * stack)25368d75effSDimitry Andric void ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack) {
25468d75effSDimitry Andric ScopedInErrorReport in_report;
25568d75effSDimitry Andric ErrorMallocUsableSizeNotOwned error(GetCurrentTidOrInvalid(), stack, addr);
25668d75effSDimitry Andric in_report.ReportError(error);
25768d75effSDimitry Andric }
25868d75effSDimitry Andric
ReportSanitizerGetAllocatedSizeNotOwned(uptr addr,BufferedStackTrace * stack)25968d75effSDimitry Andric void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr,
26068d75effSDimitry Andric BufferedStackTrace *stack) {
26168d75effSDimitry Andric ScopedInErrorReport in_report;
26268d75effSDimitry Andric ErrorSanitizerGetAllocatedSizeNotOwned error(GetCurrentTidOrInvalid(), stack,
26368d75effSDimitry Andric addr);
26468d75effSDimitry Andric in_report.ReportError(error);
26568d75effSDimitry Andric }
26668d75effSDimitry Andric
ReportCallocOverflow(uptr count,uptr size,BufferedStackTrace * stack)26768d75effSDimitry Andric void ReportCallocOverflow(uptr count, uptr size, BufferedStackTrace *stack) {
26868d75effSDimitry Andric ScopedInErrorReport in_report(/*fatal*/ true);
26968d75effSDimitry Andric ErrorCallocOverflow error(GetCurrentTidOrInvalid(), stack, count, size);
27068d75effSDimitry Andric in_report.ReportError(error);
27168d75effSDimitry Andric }
27268d75effSDimitry Andric
ReportReallocArrayOverflow(uptr count,uptr size,BufferedStackTrace * stack)27368d75effSDimitry Andric void ReportReallocArrayOverflow(uptr count, uptr size,
27468d75effSDimitry Andric BufferedStackTrace *stack) {
27568d75effSDimitry Andric ScopedInErrorReport in_report(/*fatal*/ true);
27668d75effSDimitry Andric ErrorReallocArrayOverflow error(GetCurrentTidOrInvalid(), stack, count, size);
27768d75effSDimitry Andric in_report.ReportError(error);
27868d75effSDimitry Andric }
27968d75effSDimitry Andric
ReportPvallocOverflow(uptr size,BufferedStackTrace * stack)28068d75effSDimitry Andric void ReportPvallocOverflow(uptr size, BufferedStackTrace *stack) {
28168d75effSDimitry Andric ScopedInErrorReport in_report(/*fatal*/ true);
28268d75effSDimitry Andric ErrorPvallocOverflow error(GetCurrentTidOrInvalid(), stack, size);
28368d75effSDimitry Andric in_report.ReportError(error);
28468d75effSDimitry Andric }
28568d75effSDimitry Andric
ReportInvalidAllocationAlignment(uptr alignment,BufferedStackTrace * stack)28668d75effSDimitry Andric void ReportInvalidAllocationAlignment(uptr alignment,
28768d75effSDimitry Andric BufferedStackTrace *stack) {
28868d75effSDimitry Andric ScopedInErrorReport in_report(/*fatal*/ true);
28968d75effSDimitry Andric ErrorInvalidAllocationAlignment error(GetCurrentTidOrInvalid(), stack,
29068d75effSDimitry Andric alignment);
29168d75effSDimitry Andric in_report.ReportError(error);
29268d75effSDimitry Andric }
29368d75effSDimitry Andric
ReportInvalidAlignedAllocAlignment(uptr size,uptr alignment,BufferedStackTrace * stack)29468d75effSDimitry Andric void ReportInvalidAlignedAllocAlignment(uptr size, uptr alignment,
29568d75effSDimitry Andric BufferedStackTrace *stack) {
29668d75effSDimitry Andric ScopedInErrorReport in_report(/*fatal*/ true);
29768d75effSDimitry Andric ErrorInvalidAlignedAllocAlignment error(GetCurrentTidOrInvalid(), stack,
29868d75effSDimitry Andric size, alignment);
29968d75effSDimitry Andric in_report.ReportError(error);
30068d75effSDimitry Andric }
30168d75effSDimitry Andric
ReportInvalidPosixMemalignAlignment(uptr alignment,BufferedStackTrace * stack)30268d75effSDimitry Andric void ReportInvalidPosixMemalignAlignment(uptr alignment,
30368d75effSDimitry Andric BufferedStackTrace *stack) {
30468d75effSDimitry Andric ScopedInErrorReport in_report(/*fatal*/ true);
30568d75effSDimitry Andric ErrorInvalidPosixMemalignAlignment error(GetCurrentTidOrInvalid(), stack,
30668d75effSDimitry Andric alignment);
30768d75effSDimitry Andric in_report.ReportError(error);
30868d75effSDimitry Andric }
30968d75effSDimitry Andric
ReportAllocationSizeTooBig(uptr user_size,uptr total_size,uptr max_size,BufferedStackTrace * stack)31068d75effSDimitry Andric void ReportAllocationSizeTooBig(uptr user_size, uptr total_size, uptr max_size,
31168d75effSDimitry Andric BufferedStackTrace *stack) {
31268d75effSDimitry Andric ScopedInErrorReport in_report(/*fatal*/ true);
31368d75effSDimitry Andric ErrorAllocationSizeTooBig error(GetCurrentTidOrInvalid(), stack, user_size,
31468d75effSDimitry Andric total_size, max_size);
31568d75effSDimitry Andric in_report.ReportError(error);
31668d75effSDimitry Andric }
31768d75effSDimitry Andric
ReportRssLimitExceeded(BufferedStackTrace * stack)31868d75effSDimitry Andric void ReportRssLimitExceeded(BufferedStackTrace *stack) {
31968d75effSDimitry Andric ScopedInErrorReport in_report(/*fatal*/ true);
32068d75effSDimitry Andric ErrorRssLimitExceeded error(GetCurrentTidOrInvalid(), stack);
32168d75effSDimitry Andric in_report.ReportError(error);
32268d75effSDimitry Andric }
32368d75effSDimitry Andric
ReportOutOfMemory(uptr requested_size,BufferedStackTrace * stack)32468d75effSDimitry Andric void ReportOutOfMemory(uptr requested_size, BufferedStackTrace *stack) {
32568d75effSDimitry Andric ScopedInErrorReport in_report(/*fatal*/ true);
32668d75effSDimitry Andric ErrorOutOfMemory error(GetCurrentTidOrInvalid(), stack, requested_size);
32768d75effSDimitry Andric in_report.ReportError(error);
32868d75effSDimitry Andric }
32968d75effSDimitry Andric
ReportStringFunctionMemoryRangesOverlap(const char * function,const char * offset1,uptr length1,const char * offset2,uptr length2,BufferedStackTrace * stack)33068d75effSDimitry Andric void ReportStringFunctionMemoryRangesOverlap(const char *function,
33168d75effSDimitry Andric const char *offset1, uptr length1,
33268d75effSDimitry Andric const char *offset2, uptr length2,
33368d75effSDimitry Andric BufferedStackTrace *stack) {
33468d75effSDimitry Andric ScopedInErrorReport in_report;
33568d75effSDimitry Andric ErrorStringFunctionMemoryRangesOverlap error(
33668d75effSDimitry Andric GetCurrentTidOrInvalid(), stack, (uptr)offset1, length1, (uptr)offset2,
33768d75effSDimitry Andric length2, function);
33868d75effSDimitry Andric in_report.ReportError(error);
33968d75effSDimitry Andric }
34068d75effSDimitry Andric
ReportStringFunctionSizeOverflow(uptr offset,uptr size,BufferedStackTrace * stack)34168d75effSDimitry Andric void ReportStringFunctionSizeOverflow(uptr offset, uptr size,
34268d75effSDimitry Andric BufferedStackTrace *stack) {
34368d75effSDimitry Andric ScopedInErrorReport in_report;
34468d75effSDimitry Andric ErrorStringFunctionSizeOverflow error(GetCurrentTidOrInvalid(), stack, offset,
34568d75effSDimitry Andric size);
34668d75effSDimitry Andric in_report.ReportError(error);
34768d75effSDimitry Andric }
34868d75effSDimitry Andric
ReportBadParamsToAnnotateContiguousContainer(uptr beg,uptr end,uptr old_mid,uptr new_mid,BufferedStackTrace * stack)34968d75effSDimitry Andric void ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end,
35068d75effSDimitry Andric uptr old_mid, uptr new_mid,
35168d75effSDimitry Andric BufferedStackTrace *stack) {
35268d75effSDimitry Andric ScopedInErrorReport in_report;
35368d75effSDimitry Andric ErrorBadParamsToAnnotateContiguousContainer error(
35468d75effSDimitry Andric GetCurrentTidOrInvalid(), stack, beg, end, old_mid, new_mid);
35568d75effSDimitry Andric in_report.ReportError(error);
35668d75effSDimitry Andric }
35768d75effSDimitry Andric
ReportBadParamsToAnnotateDoubleEndedContiguousContainer(uptr storage_beg,uptr storage_end,uptr old_container_beg,uptr old_container_end,uptr new_container_beg,uptr new_container_end,BufferedStackTrace * stack)358bdd1243dSDimitry Andric void ReportBadParamsToAnnotateDoubleEndedContiguousContainer(
359bdd1243dSDimitry Andric uptr storage_beg, uptr storage_end, uptr old_container_beg,
360bdd1243dSDimitry Andric uptr old_container_end, uptr new_container_beg, uptr new_container_end,
361bdd1243dSDimitry Andric BufferedStackTrace *stack) {
362bdd1243dSDimitry Andric ScopedInErrorReport in_report;
363bdd1243dSDimitry Andric ErrorBadParamsToAnnotateDoubleEndedContiguousContainer error(
364bdd1243dSDimitry Andric GetCurrentTidOrInvalid(), stack, storage_beg, storage_end,
365bdd1243dSDimitry Andric old_container_beg, old_container_end, new_container_beg,
366bdd1243dSDimitry Andric new_container_end);
367bdd1243dSDimitry Andric in_report.ReportError(error);
368bdd1243dSDimitry Andric }
369bdd1243dSDimitry Andric
ReportODRViolation(const __asan_global * g1,u32 stack_id1,const __asan_global * g2,u32 stack_id2)37068d75effSDimitry Andric void ReportODRViolation(const __asan_global *g1, u32 stack_id1,
37168d75effSDimitry Andric const __asan_global *g2, u32 stack_id2) {
37268d75effSDimitry Andric ScopedInErrorReport in_report;
37368d75effSDimitry Andric ErrorODRViolation error(GetCurrentTidOrInvalid(), g1, stack_id1, g2,
37468d75effSDimitry Andric stack_id2);
37568d75effSDimitry Andric in_report.ReportError(error);
37668d75effSDimitry Andric }
37768d75effSDimitry Andric
37868d75effSDimitry Andric // ----------------------- CheckForInvalidPointerPair ----------- {{{1
ReportInvalidPointerPair(uptr pc,uptr bp,uptr sp,uptr a1,uptr a2)37968d75effSDimitry Andric static NOINLINE void ReportInvalidPointerPair(uptr pc, uptr bp, uptr sp,
38068d75effSDimitry Andric uptr a1, uptr a2) {
38168d75effSDimitry Andric ScopedInErrorReport in_report;
38268d75effSDimitry Andric ErrorInvalidPointerPair error(GetCurrentTidOrInvalid(), pc, bp, sp, a1, a2);
38368d75effSDimitry Andric in_report.ReportError(error);
38468d75effSDimitry Andric }
38568d75effSDimitry Andric
IsInvalidPointerPair(uptr a1,uptr a2)38668d75effSDimitry Andric static bool IsInvalidPointerPair(uptr a1, uptr a2) {
38768d75effSDimitry Andric if (a1 == a2)
38868d75effSDimitry Andric return false;
38968d75effSDimitry Andric
39068d75effSDimitry Andric // 256B in shadow memory can be iterated quite fast
39168d75effSDimitry Andric static const uptr kMaxOffset = 2048;
39268d75effSDimitry Andric
39368d75effSDimitry Andric uptr left = a1 < a2 ? a1 : a2;
39468d75effSDimitry Andric uptr right = a1 < a2 ? a2 : a1;
39568d75effSDimitry Andric uptr offset = right - left;
39668d75effSDimitry Andric if (offset <= kMaxOffset)
39768d75effSDimitry Andric return __asan_region_is_poisoned(left, offset);
39868d75effSDimitry Andric
39968d75effSDimitry Andric AsanThread *t = GetCurrentThread();
40068d75effSDimitry Andric
40168d75effSDimitry Andric // check whether left is a stack memory pointer
40268d75effSDimitry Andric if (uptr shadow_offset1 = t->GetStackVariableShadowStart(left)) {
40368d75effSDimitry Andric uptr shadow_offset2 = t->GetStackVariableShadowStart(right);
40468d75effSDimitry Andric return shadow_offset2 == 0 || shadow_offset1 != shadow_offset2;
40568d75effSDimitry Andric }
40668d75effSDimitry Andric
40768d75effSDimitry Andric // check whether left is a heap memory address
40868d75effSDimitry Andric HeapAddressDescription hdesc1, hdesc2;
40968d75effSDimitry Andric if (GetHeapAddressInformation(left, 0, &hdesc1) &&
41068d75effSDimitry Andric hdesc1.chunk_access.access_type == kAccessTypeInside)
41168d75effSDimitry Andric return !GetHeapAddressInformation(right, 0, &hdesc2) ||
41268d75effSDimitry Andric hdesc2.chunk_access.access_type != kAccessTypeInside ||
41368d75effSDimitry Andric hdesc1.chunk_access.chunk_begin != hdesc2.chunk_access.chunk_begin;
41468d75effSDimitry Andric
41568d75effSDimitry Andric // check whether left is an address of a global variable
41668d75effSDimitry Andric GlobalAddressDescription gdesc1, gdesc2;
41768d75effSDimitry Andric if (GetGlobalAddressInformation(left, 0, &gdesc1))
41868d75effSDimitry Andric return !GetGlobalAddressInformation(right - 1, 0, &gdesc2) ||
41968d75effSDimitry Andric !gdesc1.PointsInsideTheSameVariable(gdesc2);
42068d75effSDimitry Andric
42168d75effSDimitry Andric if (t->GetStackVariableShadowStart(right) ||
42268d75effSDimitry Andric GetHeapAddressInformation(right, 0, &hdesc2) ||
42368d75effSDimitry Andric GetGlobalAddressInformation(right - 1, 0, &gdesc2))
42468d75effSDimitry Andric return true;
42568d75effSDimitry Andric
42668d75effSDimitry Andric // At this point we know nothing about both a1 and a2 addresses.
42768d75effSDimitry Andric return false;
42868d75effSDimitry Andric }
42968d75effSDimitry Andric
CheckForInvalidPointerPair(void * p1,void * p2)430e8d8bef9SDimitry Andric static inline void CheckForInvalidPointerPair(void *p1, void *p2) {
43168d75effSDimitry Andric switch (flags()->detect_invalid_pointer_pairs) {
43268d75effSDimitry Andric case 0:
43368d75effSDimitry Andric return;
43468d75effSDimitry Andric case 1:
43568d75effSDimitry Andric if (p1 == nullptr || p2 == nullptr)
43668d75effSDimitry Andric return;
43768d75effSDimitry Andric break;
43868d75effSDimitry Andric }
43968d75effSDimitry Andric
44068d75effSDimitry Andric uptr a1 = reinterpret_cast<uptr>(p1);
44168d75effSDimitry Andric uptr a2 = reinterpret_cast<uptr>(p2);
44268d75effSDimitry Andric
44368d75effSDimitry Andric if (IsInvalidPointerPair(a1, a2)) {
44468d75effSDimitry Andric GET_CALLER_PC_BP_SP;
44568d75effSDimitry Andric ReportInvalidPointerPair(pc, bp, sp, a1, a2);
44668d75effSDimitry Andric }
44768d75effSDimitry Andric }
44868d75effSDimitry Andric // ----------------------- Mac-specific reports ----------------- {{{1
44968d75effSDimitry Andric
ReportMacMzReallocUnknown(uptr addr,uptr zone_ptr,const char * zone_name,BufferedStackTrace * stack)45068d75effSDimitry Andric void ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name,
45168d75effSDimitry Andric BufferedStackTrace *stack) {
45268d75effSDimitry Andric ScopedInErrorReport in_report;
453349cc55cSDimitry Andric Printf(
454349cc55cSDimitry Andric "mz_realloc(%p) -- attempting to realloc unallocated memory.\n"
45568d75effSDimitry Andric "This is an unrecoverable problem, exiting now.\n",
456349cc55cSDimitry Andric (void *)addr);
45768d75effSDimitry Andric PrintZoneForPointer(addr, zone_ptr, zone_name);
45868d75effSDimitry Andric stack->Print();
45968d75effSDimitry Andric DescribeAddressIfHeap(addr);
46068d75effSDimitry Andric }
46168d75effSDimitry Andric
46268d75effSDimitry Andric // -------------- SuppressErrorReport -------------- {{{1
46368d75effSDimitry Andric // Avoid error reports duplicating for ASan recover mode.
SuppressErrorReport(uptr pc)46468d75effSDimitry Andric static bool SuppressErrorReport(uptr pc) {
46568d75effSDimitry Andric if (!common_flags()->suppress_equal_pcs) return false;
46668d75effSDimitry Andric for (unsigned i = 0; i < kAsanBuggyPcPoolSize; i++) {
46768d75effSDimitry Andric uptr cmp = atomic_load_relaxed(&AsanBuggyPcPool[i]);
46868d75effSDimitry Andric if (cmp == 0 && atomic_compare_exchange_strong(&AsanBuggyPcPool[i], &cmp,
46968d75effSDimitry Andric pc, memory_order_relaxed))
47068d75effSDimitry Andric return false;
47168d75effSDimitry Andric if (cmp == pc) return true;
47268d75effSDimitry Andric }
47368d75effSDimitry Andric Die();
47468d75effSDimitry Andric }
47568d75effSDimitry Andric
ReportGenericError(uptr pc,uptr bp,uptr sp,uptr addr,bool is_write,uptr access_size,u32 exp,bool fatal)47668d75effSDimitry Andric void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write,
47768d75effSDimitry Andric uptr access_size, u32 exp, bool fatal) {
4784824e7fdSDimitry Andric if (__asan_test_only_reported_buggy_pointer) {
4794824e7fdSDimitry Andric *__asan_test_only_reported_buggy_pointer = addr;
4804824e7fdSDimitry Andric return;
4814824e7fdSDimitry Andric }
48268d75effSDimitry Andric if (!fatal && SuppressErrorReport(pc)) return;
48368d75effSDimitry Andric ENABLE_FRAME_POINTER;
48468d75effSDimitry Andric
48568d75effSDimitry Andric // Optimization experiments.
48668d75effSDimitry Andric // The experiments can be used to evaluate potential optimizations that remove
48768d75effSDimitry Andric // instrumentation (assess false negatives). Instead of completely removing
48868d75effSDimitry Andric // some instrumentation, compiler can emit special calls into runtime
48968d75effSDimitry Andric // (e.g. __asan_report_exp_load1 instead of __asan_report_load1) and pass
49068d75effSDimitry Andric // mask of experiments (exp).
49168d75effSDimitry Andric // The reaction to a non-zero value of exp is to be defined.
49268d75effSDimitry Andric (void)exp;
49368d75effSDimitry Andric
49468d75effSDimitry Andric ScopedInErrorReport in_report(fatal);
49568d75effSDimitry Andric ErrorGeneric error(GetCurrentTidOrInvalid(), pc, bp, sp, addr, is_write,
49668d75effSDimitry Andric access_size);
49768d75effSDimitry Andric in_report.ReportError(error);
49868d75effSDimitry Andric }
49968d75effSDimitry Andric
50068d75effSDimitry Andric } // namespace __asan
50168d75effSDimitry Andric
50268d75effSDimitry Andric // --------------------------- Interface --------------------- {{{1
50368d75effSDimitry Andric using namespace __asan;
50468d75effSDimitry Andric
__asan_report_error(uptr pc,uptr bp,uptr sp,uptr addr,int is_write,uptr access_size,u32 exp)50568d75effSDimitry Andric void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write,
50668d75effSDimitry Andric uptr access_size, u32 exp) {
50768d75effSDimitry Andric ENABLE_FRAME_POINTER;
50868d75effSDimitry Andric bool fatal = flags()->halt_on_error;
50968d75effSDimitry Andric ReportGenericError(pc, bp, sp, addr, is_write, access_size, exp, fatal);
51068d75effSDimitry Andric }
51168d75effSDimitry Andric
__asan_set_error_report_callback(void (* callback)(const char *))51268d75effSDimitry Andric void NOINLINE __asan_set_error_report_callback(void (*callback)(const char*)) {
513349cc55cSDimitry Andric Lock l(&error_message_buf_mutex);
51468d75effSDimitry Andric error_report_callback = callback;
51568d75effSDimitry Andric }
51668d75effSDimitry Andric
__asan_describe_address(uptr addr)51768d75effSDimitry Andric void __asan_describe_address(uptr addr) {
51868d75effSDimitry Andric // Thread registry must be locked while we're describing an address.
51968d75effSDimitry Andric asanThreadRegistry().Lock();
52068d75effSDimitry Andric PrintAddressDescription(addr, 1, "");
52168d75effSDimitry Andric asanThreadRegistry().Unlock();
52268d75effSDimitry Andric }
52368d75effSDimitry Andric
__asan_report_present()52468d75effSDimitry Andric int __asan_report_present() {
52568d75effSDimitry Andric return ScopedInErrorReport::CurrentError().kind != kErrorKindInvalid;
52668d75effSDimitry Andric }
52768d75effSDimitry Andric
__asan_get_report_pc()52868d75effSDimitry Andric uptr __asan_get_report_pc() {
52968d75effSDimitry Andric if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
53068d75effSDimitry Andric return ScopedInErrorReport::CurrentError().Generic.pc;
53168d75effSDimitry Andric return 0;
53268d75effSDimitry Andric }
53368d75effSDimitry Andric
__asan_get_report_bp()53468d75effSDimitry Andric uptr __asan_get_report_bp() {
53568d75effSDimitry Andric if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
53668d75effSDimitry Andric return ScopedInErrorReport::CurrentError().Generic.bp;
53768d75effSDimitry Andric return 0;
53868d75effSDimitry Andric }
53968d75effSDimitry Andric
__asan_get_report_sp()54068d75effSDimitry Andric uptr __asan_get_report_sp() {
54168d75effSDimitry Andric if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
54268d75effSDimitry Andric return ScopedInErrorReport::CurrentError().Generic.sp;
54368d75effSDimitry Andric return 0;
54468d75effSDimitry Andric }
54568d75effSDimitry Andric
__asan_get_report_address()54668d75effSDimitry Andric uptr __asan_get_report_address() {
54768d75effSDimitry Andric ErrorDescription &err = ScopedInErrorReport::CurrentError();
54868d75effSDimitry Andric if (err.kind == kErrorKindGeneric)
54968d75effSDimitry Andric return err.Generic.addr_description.Address();
55068d75effSDimitry Andric else if (err.kind == kErrorKindDoubleFree)
55168d75effSDimitry Andric return err.DoubleFree.addr_description.addr;
55268d75effSDimitry Andric return 0;
55368d75effSDimitry Andric }
55468d75effSDimitry Andric
__asan_get_report_access_type()55568d75effSDimitry Andric int __asan_get_report_access_type() {
55668d75effSDimitry Andric if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
55768d75effSDimitry Andric return ScopedInErrorReport::CurrentError().Generic.is_write;
55868d75effSDimitry Andric return 0;
55968d75effSDimitry Andric }
56068d75effSDimitry Andric
__asan_get_report_access_size()56168d75effSDimitry Andric uptr __asan_get_report_access_size() {
56268d75effSDimitry Andric if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
56368d75effSDimitry Andric return ScopedInErrorReport::CurrentError().Generic.access_size;
56468d75effSDimitry Andric return 0;
56568d75effSDimitry Andric }
56668d75effSDimitry Andric
__asan_get_report_description()56768d75effSDimitry Andric const char *__asan_get_report_description() {
56868d75effSDimitry Andric if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
56968d75effSDimitry Andric return ScopedInErrorReport::CurrentError().Generic.bug_descr;
57068d75effSDimitry Andric return ScopedInErrorReport::CurrentError().Base.scariness.GetDescription();
57168d75effSDimitry Andric }
57268d75effSDimitry Andric
57368d75effSDimitry Andric extern "C" {
57468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
__sanitizer_ptr_sub(void * a,void * b)57568d75effSDimitry Andric void __sanitizer_ptr_sub(void *a, void *b) {
57668d75effSDimitry Andric CheckForInvalidPointerPair(a, b);
57768d75effSDimitry Andric }
57868d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
__sanitizer_ptr_cmp(void * a,void * b)57968d75effSDimitry Andric void __sanitizer_ptr_cmp(void *a, void *b) {
58068d75effSDimitry Andric CheckForInvalidPointerPair(a, b);
58168d75effSDimitry Andric }
58268d75effSDimitry Andric } // extern "C"
58368d75effSDimitry Andric
58468d75effSDimitry Andric // Provide default implementation of __asan_on_error that does nothing
58568d75effSDimitry Andric // and may be overriden by user.
SANITIZER_INTERFACE_WEAK_DEF(void,__asan_on_error,void)58668d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __asan_on_error, void) {}
587