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