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