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 
154*e8d8bef9SDimitry Andric     if (common_flags()->print_module_map == 2)
155*e8d8bef9SDimitry Andric       DumpProcessMap();
15668d75effSDimitry Andric 
15768d75effSDimitry Andric     // Copy the message buffer so that we could start logging without holding a
15868d75effSDimitry Andric     // lock that gets aquired during printing.
15968d75effSDimitry Andric     InternalMmapVector<char> buffer_copy(kErrorMessageBufferSize);
16068d75effSDimitry Andric     {
16168d75effSDimitry Andric       BlockingMutexLock l(&error_message_buf_mutex);
16268d75effSDimitry Andric       internal_memcpy(buffer_copy.data(),
16368d75effSDimitry Andric                       error_message_buffer, kErrorMessageBufferSize);
1645ffd83dbSDimitry Andric       // Clear error_message_buffer so that if we find other errors
1655ffd83dbSDimitry Andric       // we don't re-log this error.
1665ffd83dbSDimitry Andric       error_message_buffer_pos = 0;
16768d75effSDimitry Andric     }
16868d75effSDimitry Andric 
16968d75effSDimitry Andric     LogFullErrorReport(buffer_copy.data());
17068d75effSDimitry Andric 
17168d75effSDimitry Andric     if (error_report_callback) {
17268d75effSDimitry Andric       error_report_callback(buffer_copy.data());
17368d75effSDimitry Andric     }
17468d75effSDimitry Andric 
17568d75effSDimitry Andric     if (halt_on_error_ && common_flags()->abort_on_error) {
17668d75effSDimitry Andric       // On Android the message is truncated to 512 characters.
17768d75effSDimitry Andric       // FIXME: implement "compact" error format, possibly without, or with
17868d75effSDimitry Andric       // highly compressed stack traces?
17968d75effSDimitry Andric       // FIXME: or just use the summary line as abort message?
18068d75effSDimitry Andric       SetAbortMessage(buffer_copy.data());
18168d75effSDimitry Andric     }
18268d75effSDimitry Andric 
18368d75effSDimitry Andric     // In halt_on_error = false mode, reset the current error object (before
18468d75effSDimitry Andric     // unlocking).
18568d75effSDimitry Andric     if (!halt_on_error_)
18668d75effSDimitry Andric       internal_memset(&current_error_, 0, sizeof(current_error_));
18768d75effSDimitry Andric 
18868d75effSDimitry Andric     if (halt_on_error_) {
18968d75effSDimitry Andric       Report("ABORTING\n");
19068d75effSDimitry Andric       Die();
19168d75effSDimitry Andric     }
19268d75effSDimitry Andric   }
19368d75effSDimitry Andric 
19468d75effSDimitry Andric   void ReportError(const ErrorDescription &description) {
19568d75effSDimitry Andric     // Can only report one error per ScopedInErrorReport.
19668d75effSDimitry Andric     CHECK_EQ(current_error_.kind, kErrorKindInvalid);
19768d75effSDimitry Andric     internal_memcpy(&current_error_, &description, sizeof(current_error_));
19868d75effSDimitry Andric   }
19968d75effSDimitry Andric 
20068d75effSDimitry Andric   static ErrorDescription &CurrentError() {
20168d75effSDimitry Andric     return current_error_;
20268d75effSDimitry Andric   }
20368d75effSDimitry Andric 
20468d75effSDimitry Andric  private:
20568d75effSDimitry Andric   ScopedErrorReportLock error_report_lock_;
20668d75effSDimitry Andric   // Error currently being reported. This enables the destructor to interact
20768d75effSDimitry Andric   // with the debugger and point it to an error description.
20868d75effSDimitry Andric   static ErrorDescription current_error_;
20968d75effSDimitry Andric   bool halt_on_error_;
21068d75effSDimitry Andric };
21168d75effSDimitry Andric 
21268d75effSDimitry Andric ErrorDescription ScopedInErrorReport::current_error_(LINKER_INITIALIZED);
21368d75effSDimitry Andric 
21468d75effSDimitry Andric void ReportDeadlySignal(const SignalContext &sig) {
21568d75effSDimitry Andric   ScopedInErrorReport in_report(/*fatal*/ true);
21668d75effSDimitry Andric   ErrorDeadlySignal error(GetCurrentTidOrInvalid(), sig);
21768d75effSDimitry Andric   in_report.ReportError(error);
21868d75effSDimitry Andric }
21968d75effSDimitry Andric 
22068d75effSDimitry Andric void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack) {
22168d75effSDimitry Andric   ScopedInErrorReport in_report;
22268d75effSDimitry Andric   ErrorDoubleFree error(GetCurrentTidOrInvalid(), free_stack, addr);
22368d75effSDimitry Andric   in_report.ReportError(error);
22468d75effSDimitry Andric }
22568d75effSDimitry Andric 
22668d75effSDimitry Andric void ReportNewDeleteTypeMismatch(uptr addr, uptr delete_size,
22768d75effSDimitry Andric                                  uptr delete_alignment,
22868d75effSDimitry Andric                                  BufferedStackTrace *free_stack) {
22968d75effSDimitry Andric   ScopedInErrorReport in_report;
23068d75effSDimitry Andric   ErrorNewDeleteTypeMismatch error(GetCurrentTidOrInvalid(), free_stack, addr,
23168d75effSDimitry Andric                                    delete_size, delete_alignment);
23268d75effSDimitry Andric   in_report.ReportError(error);
23368d75effSDimitry Andric }
23468d75effSDimitry Andric 
23568d75effSDimitry Andric void ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack) {
23668d75effSDimitry Andric   ScopedInErrorReport in_report;
23768d75effSDimitry Andric   ErrorFreeNotMalloced error(GetCurrentTidOrInvalid(), free_stack, addr);
23868d75effSDimitry Andric   in_report.ReportError(error);
23968d75effSDimitry Andric }
24068d75effSDimitry Andric 
24168d75effSDimitry Andric void ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack,
24268d75effSDimitry Andric                              AllocType alloc_type,
24368d75effSDimitry Andric                              AllocType dealloc_type) {
24468d75effSDimitry Andric   ScopedInErrorReport in_report;
24568d75effSDimitry Andric   ErrorAllocTypeMismatch error(GetCurrentTidOrInvalid(), free_stack, addr,
24668d75effSDimitry Andric                                alloc_type, dealloc_type);
24768d75effSDimitry Andric   in_report.ReportError(error);
24868d75effSDimitry Andric }
24968d75effSDimitry Andric 
25068d75effSDimitry Andric void ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack) {
25168d75effSDimitry Andric   ScopedInErrorReport in_report;
25268d75effSDimitry Andric   ErrorMallocUsableSizeNotOwned error(GetCurrentTidOrInvalid(), stack, addr);
25368d75effSDimitry Andric   in_report.ReportError(error);
25468d75effSDimitry Andric }
25568d75effSDimitry Andric 
25668d75effSDimitry Andric void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr,
25768d75effSDimitry Andric                                              BufferedStackTrace *stack) {
25868d75effSDimitry Andric   ScopedInErrorReport in_report;
25968d75effSDimitry Andric   ErrorSanitizerGetAllocatedSizeNotOwned error(GetCurrentTidOrInvalid(), stack,
26068d75effSDimitry Andric                                                addr);
26168d75effSDimitry Andric   in_report.ReportError(error);
26268d75effSDimitry Andric }
26368d75effSDimitry Andric 
26468d75effSDimitry Andric void ReportCallocOverflow(uptr count, uptr size, BufferedStackTrace *stack) {
26568d75effSDimitry Andric   ScopedInErrorReport in_report(/*fatal*/ true);
26668d75effSDimitry Andric   ErrorCallocOverflow error(GetCurrentTidOrInvalid(), stack, count, size);
26768d75effSDimitry Andric   in_report.ReportError(error);
26868d75effSDimitry Andric }
26968d75effSDimitry Andric 
27068d75effSDimitry Andric void ReportReallocArrayOverflow(uptr count, uptr size,
27168d75effSDimitry Andric                                 BufferedStackTrace *stack) {
27268d75effSDimitry Andric   ScopedInErrorReport in_report(/*fatal*/ true);
27368d75effSDimitry Andric   ErrorReallocArrayOverflow error(GetCurrentTidOrInvalid(), stack, count, size);
27468d75effSDimitry Andric   in_report.ReportError(error);
27568d75effSDimitry Andric }
27668d75effSDimitry Andric 
27768d75effSDimitry Andric void ReportPvallocOverflow(uptr size, BufferedStackTrace *stack) {
27868d75effSDimitry Andric   ScopedInErrorReport in_report(/*fatal*/ true);
27968d75effSDimitry Andric   ErrorPvallocOverflow error(GetCurrentTidOrInvalid(), stack, size);
28068d75effSDimitry Andric   in_report.ReportError(error);
28168d75effSDimitry Andric }
28268d75effSDimitry Andric 
28368d75effSDimitry Andric void ReportInvalidAllocationAlignment(uptr alignment,
28468d75effSDimitry Andric                                       BufferedStackTrace *stack) {
28568d75effSDimitry Andric   ScopedInErrorReport in_report(/*fatal*/ true);
28668d75effSDimitry Andric   ErrorInvalidAllocationAlignment error(GetCurrentTidOrInvalid(), stack,
28768d75effSDimitry Andric                                         alignment);
28868d75effSDimitry Andric   in_report.ReportError(error);
28968d75effSDimitry Andric }
29068d75effSDimitry Andric 
29168d75effSDimitry Andric void ReportInvalidAlignedAllocAlignment(uptr size, uptr alignment,
29268d75effSDimitry Andric                                         BufferedStackTrace *stack) {
29368d75effSDimitry Andric   ScopedInErrorReport in_report(/*fatal*/ true);
29468d75effSDimitry Andric   ErrorInvalidAlignedAllocAlignment error(GetCurrentTidOrInvalid(), stack,
29568d75effSDimitry Andric                                           size, alignment);
29668d75effSDimitry Andric   in_report.ReportError(error);
29768d75effSDimitry Andric }
29868d75effSDimitry Andric 
29968d75effSDimitry Andric void ReportInvalidPosixMemalignAlignment(uptr alignment,
30068d75effSDimitry Andric                                          BufferedStackTrace *stack) {
30168d75effSDimitry Andric   ScopedInErrorReport in_report(/*fatal*/ true);
30268d75effSDimitry Andric   ErrorInvalidPosixMemalignAlignment error(GetCurrentTidOrInvalid(), stack,
30368d75effSDimitry Andric                                            alignment);
30468d75effSDimitry Andric   in_report.ReportError(error);
30568d75effSDimitry Andric }
30668d75effSDimitry Andric 
30768d75effSDimitry Andric void ReportAllocationSizeTooBig(uptr user_size, uptr total_size, uptr max_size,
30868d75effSDimitry Andric                                 BufferedStackTrace *stack) {
30968d75effSDimitry Andric   ScopedInErrorReport in_report(/*fatal*/ true);
31068d75effSDimitry Andric   ErrorAllocationSizeTooBig error(GetCurrentTidOrInvalid(), stack, user_size,
31168d75effSDimitry Andric                                   total_size, max_size);
31268d75effSDimitry Andric   in_report.ReportError(error);
31368d75effSDimitry Andric }
31468d75effSDimitry Andric 
31568d75effSDimitry Andric void ReportRssLimitExceeded(BufferedStackTrace *stack) {
31668d75effSDimitry Andric   ScopedInErrorReport in_report(/*fatal*/ true);
31768d75effSDimitry Andric   ErrorRssLimitExceeded error(GetCurrentTidOrInvalid(), stack);
31868d75effSDimitry Andric   in_report.ReportError(error);
31968d75effSDimitry Andric }
32068d75effSDimitry Andric 
32168d75effSDimitry Andric void ReportOutOfMemory(uptr requested_size, BufferedStackTrace *stack) {
32268d75effSDimitry Andric   ScopedInErrorReport in_report(/*fatal*/ true);
32368d75effSDimitry Andric   ErrorOutOfMemory error(GetCurrentTidOrInvalid(), stack, requested_size);
32468d75effSDimitry Andric   in_report.ReportError(error);
32568d75effSDimitry Andric }
32668d75effSDimitry Andric 
32768d75effSDimitry Andric void ReportStringFunctionMemoryRangesOverlap(const char *function,
32868d75effSDimitry Andric                                              const char *offset1, uptr length1,
32968d75effSDimitry Andric                                              const char *offset2, uptr length2,
33068d75effSDimitry Andric                                              BufferedStackTrace *stack) {
33168d75effSDimitry Andric   ScopedInErrorReport in_report;
33268d75effSDimitry Andric   ErrorStringFunctionMemoryRangesOverlap error(
33368d75effSDimitry Andric       GetCurrentTidOrInvalid(), stack, (uptr)offset1, length1, (uptr)offset2,
33468d75effSDimitry Andric       length2, function);
33568d75effSDimitry Andric   in_report.ReportError(error);
33668d75effSDimitry Andric }
33768d75effSDimitry Andric 
33868d75effSDimitry Andric void ReportStringFunctionSizeOverflow(uptr offset, uptr size,
33968d75effSDimitry Andric                                       BufferedStackTrace *stack) {
34068d75effSDimitry Andric   ScopedInErrorReport in_report;
34168d75effSDimitry Andric   ErrorStringFunctionSizeOverflow error(GetCurrentTidOrInvalid(), stack, offset,
34268d75effSDimitry Andric                                         size);
34368d75effSDimitry Andric   in_report.ReportError(error);
34468d75effSDimitry Andric }
34568d75effSDimitry Andric 
34668d75effSDimitry Andric void ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end,
34768d75effSDimitry Andric                                                   uptr old_mid, uptr new_mid,
34868d75effSDimitry Andric                                                   BufferedStackTrace *stack) {
34968d75effSDimitry Andric   ScopedInErrorReport in_report;
35068d75effSDimitry Andric   ErrorBadParamsToAnnotateContiguousContainer error(
35168d75effSDimitry Andric       GetCurrentTidOrInvalid(), stack, beg, end, old_mid, new_mid);
35268d75effSDimitry Andric   in_report.ReportError(error);
35368d75effSDimitry Andric }
35468d75effSDimitry Andric 
35568d75effSDimitry Andric void ReportODRViolation(const __asan_global *g1, u32 stack_id1,
35668d75effSDimitry Andric                         const __asan_global *g2, u32 stack_id2) {
35768d75effSDimitry Andric   ScopedInErrorReport in_report;
35868d75effSDimitry Andric   ErrorODRViolation error(GetCurrentTidOrInvalid(), g1, stack_id1, g2,
35968d75effSDimitry Andric                           stack_id2);
36068d75effSDimitry Andric   in_report.ReportError(error);
36168d75effSDimitry Andric }
36268d75effSDimitry Andric 
36368d75effSDimitry Andric // ----------------------- CheckForInvalidPointerPair ----------- {{{1
36468d75effSDimitry Andric static NOINLINE void ReportInvalidPointerPair(uptr pc, uptr bp, uptr sp,
36568d75effSDimitry Andric                                               uptr a1, uptr a2) {
36668d75effSDimitry Andric   ScopedInErrorReport in_report;
36768d75effSDimitry Andric   ErrorInvalidPointerPair error(GetCurrentTidOrInvalid(), pc, bp, sp, a1, a2);
36868d75effSDimitry Andric   in_report.ReportError(error);
36968d75effSDimitry Andric }
37068d75effSDimitry Andric 
37168d75effSDimitry Andric static bool IsInvalidPointerPair(uptr a1, uptr a2) {
37268d75effSDimitry Andric   if (a1 == a2)
37368d75effSDimitry Andric     return false;
37468d75effSDimitry Andric 
37568d75effSDimitry Andric   // 256B in shadow memory can be iterated quite fast
37668d75effSDimitry Andric   static const uptr kMaxOffset = 2048;
37768d75effSDimitry Andric 
37868d75effSDimitry Andric   uptr left = a1 < a2 ? a1 : a2;
37968d75effSDimitry Andric   uptr right = a1 < a2 ? a2 : a1;
38068d75effSDimitry Andric   uptr offset = right - left;
38168d75effSDimitry Andric   if (offset <= kMaxOffset)
38268d75effSDimitry Andric     return __asan_region_is_poisoned(left, offset);
38368d75effSDimitry Andric 
38468d75effSDimitry Andric   AsanThread *t = GetCurrentThread();
38568d75effSDimitry Andric 
38668d75effSDimitry Andric   // check whether left is a stack memory pointer
38768d75effSDimitry Andric   if (uptr shadow_offset1 = t->GetStackVariableShadowStart(left)) {
38868d75effSDimitry Andric     uptr shadow_offset2 = t->GetStackVariableShadowStart(right);
38968d75effSDimitry Andric     return shadow_offset2 == 0 || shadow_offset1 != shadow_offset2;
39068d75effSDimitry Andric   }
39168d75effSDimitry Andric 
39268d75effSDimitry Andric   // check whether left is a heap memory address
39368d75effSDimitry Andric   HeapAddressDescription hdesc1, hdesc2;
39468d75effSDimitry Andric   if (GetHeapAddressInformation(left, 0, &hdesc1) &&
39568d75effSDimitry Andric       hdesc1.chunk_access.access_type == kAccessTypeInside)
39668d75effSDimitry Andric     return !GetHeapAddressInformation(right, 0, &hdesc2) ||
39768d75effSDimitry Andric         hdesc2.chunk_access.access_type != kAccessTypeInside ||
39868d75effSDimitry Andric         hdesc1.chunk_access.chunk_begin != hdesc2.chunk_access.chunk_begin;
39968d75effSDimitry Andric 
40068d75effSDimitry Andric   // check whether left is an address of a global variable
40168d75effSDimitry Andric   GlobalAddressDescription gdesc1, gdesc2;
40268d75effSDimitry Andric   if (GetGlobalAddressInformation(left, 0, &gdesc1))
40368d75effSDimitry Andric     return !GetGlobalAddressInformation(right - 1, 0, &gdesc2) ||
40468d75effSDimitry Andric         !gdesc1.PointsInsideTheSameVariable(gdesc2);
40568d75effSDimitry Andric 
40668d75effSDimitry Andric   if (t->GetStackVariableShadowStart(right) ||
40768d75effSDimitry Andric       GetHeapAddressInformation(right, 0, &hdesc2) ||
40868d75effSDimitry Andric       GetGlobalAddressInformation(right - 1, 0, &gdesc2))
40968d75effSDimitry Andric     return true;
41068d75effSDimitry Andric 
41168d75effSDimitry Andric   // At this point we know nothing about both a1 and a2 addresses.
41268d75effSDimitry Andric   return false;
41368d75effSDimitry Andric }
41468d75effSDimitry Andric 
415*e8d8bef9SDimitry Andric static inline void CheckForInvalidPointerPair(void *p1, void *p2) {
41668d75effSDimitry Andric   switch (flags()->detect_invalid_pointer_pairs) {
41768d75effSDimitry Andric     case 0:
41868d75effSDimitry Andric       return;
41968d75effSDimitry Andric     case 1:
42068d75effSDimitry Andric       if (p1 == nullptr || p2 == nullptr)
42168d75effSDimitry Andric         return;
42268d75effSDimitry Andric       break;
42368d75effSDimitry Andric   }
42468d75effSDimitry Andric 
42568d75effSDimitry Andric   uptr a1 = reinterpret_cast<uptr>(p1);
42668d75effSDimitry Andric   uptr a2 = reinterpret_cast<uptr>(p2);
42768d75effSDimitry Andric 
42868d75effSDimitry Andric   if (IsInvalidPointerPair(a1, a2)) {
42968d75effSDimitry Andric     GET_CALLER_PC_BP_SP;
43068d75effSDimitry Andric     ReportInvalidPointerPair(pc, bp, sp, a1, a2);
43168d75effSDimitry Andric   }
43268d75effSDimitry Andric }
43368d75effSDimitry Andric // ----------------------- Mac-specific reports ----------------- {{{1
43468d75effSDimitry Andric 
43568d75effSDimitry Andric void ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name,
43668d75effSDimitry Andric                                BufferedStackTrace *stack) {
43768d75effSDimitry Andric   ScopedInErrorReport in_report;
43868d75effSDimitry Andric   Printf("mz_realloc(%p) -- attempting to realloc unallocated memory.\n"
43968d75effSDimitry Andric              "This is an unrecoverable problem, exiting now.\n",
44068d75effSDimitry Andric              addr);
44168d75effSDimitry Andric   PrintZoneForPointer(addr, zone_ptr, zone_name);
44268d75effSDimitry Andric   stack->Print();
44368d75effSDimitry Andric   DescribeAddressIfHeap(addr);
44468d75effSDimitry Andric }
44568d75effSDimitry Andric 
44668d75effSDimitry Andric // -------------- SuppressErrorReport -------------- {{{1
44768d75effSDimitry Andric // Avoid error reports duplicating for ASan recover mode.
44868d75effSDimitry Andric static bool SuppressErrorReport(uptr pc) {
44968d75effSDimitry Andric   if (!common_flags()->suppress_equal_pcs) return false;
45068d75effSDimitry Andric   for (unsigned i = 0; i < kAsanBuggyPcPoolSize; i++) {
45168d75effSDimitry Andric     uptr cmp = atomic_load_relaxed(&AsanBuggyPcPool[i]);
45268d75effSDimitry Andric     if (cmp == 0 && atomic_compare_exchange_strong(&AsanBuggyPcPool[i], &cmp,
45368d75effSDimitry Andric                                                    pc, memory_order_relaxed))
45468d75effSDimitry Andric       return false;
45568d75effSDimitry Andric     if (cmp == pc) return true;
45668d75effSDimitry Andric   }
45768d75effSDimitry Andric   Die();
45868d75effSDimitry Andric }
45968d75effSDimitry Andric 
46068d75effSDimitry Andric void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write,
46168d75effSDimitry Andric                         uptr access_size, u32 exp, bool fatal) {
46268d75effSDimitry Andric   if (!fatal && SuppressErrorReport(pc)) return;
46368d75effSDimitry Andric   ENABLE_FRAME_POINTER;
46468d75effSDimitry Andric 
46568d75effSDimitry Andric   // Optimization experiments.
46668d75effSDimitry Andric   // The experiments can be used to evaluate potential optimizations that remove
46768d75effSDimitry Andric   // instrumentation (assess false negatives). Instead of completely removing
46868d75effSDimitry Andric   // some instrumentation, compiler can emit special calls into runtime
46968d75effSDimitry Andric   // (e.g. __asan_report_exp_load1 instead of __asan_report_load1) and pass
47068d75effSDimitry Andric   // mask of experiments (exp).
47168d75effSDimitry Andric   // The reaction to a non-zero value of exp is to be defined.
47268d75effSDimitry Andric   (void)exp;
47368d75effSDimitry Andric 
47468d75effSDimitry Andric   ScopedInErrorReport in_report(fatal);
47568d75effSDimitry Andric   ErrorGeneric error(GetCurrentTidOrInvalid(), pc, bp, sp, addr, is_write,
47668d75effSDimitry Andric                      access_size);
47768d75effSDimitry Andric   in_report.ReportError(error);
47868d75effSDimitry Andric }
47968d75effSDimitry Andric 
48068d75effSDimitry Andric }  // namespace __asan
48168d75effSDimitry Andric 
48268d75effSDimitry Andric // --------------------------- Interface --------------------- {{{1
48368d75effSDimitry Andric using namespace __asan;
48468d75effSDimitry Andric 
48568d75effSDimitry Andric void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write,
48668d75effSDimitry Andric                          uptr access_size, u32 exp) {
48768d75effSDimitry Andric   ENABLE_FRAME_POINTER;
48868d75effSDimitry Andric   bool fatal = flags()->halt_on_error;
48968d75effSDimitry Andric   ReportGenericError(pc, bp, sp, addr, is_write, access_size, exp, fatal);
49068d75effSDimitry Andric }
49168d75effSDimitry Andric 
49268d75effSDimitry Andric void NOINLINE __asan_set_error_report_callback(void (*callback)(const char*)) {
49368d75effSDimitry Andric   BlockingMutexLock l(&error_message_buf_mutex);
49468d75effSDimitry Andric   error_report_callback = callback;
49568d75effSDimitry Andric }
49668d75effSDimitry Andric 
49768d75effSDimitry Andric void __asan_describe_address(uptr addr) {
49868d75effSDimitry Andric   // Thread registry must be locked while we're describing an address.
49968d75effSDimitry Andric   asanThreadRegistry().Lock();
50068d75effSDimitry Andric   PrintAddressDescription(addr, 1, "");
50168d75effSDimitry Andric   asanThreadRegistry().Unlock();
50268d75effSDimitry Andric }
50368d75effSDimitry Andric 
50468d75effSDimitry Andric int __asan_report_present() {
50568d75effSDimitry Andric   return ScopedInErrorReport::CurrentError().kind != kErrorKindInvalid;
50668d75effSDimitry Andric }
50768d75effSDimitry Andric 
50868d75effSDimitry Andric uptr __asan_get_report_pc() {
50968d75effSDimitry Andric   if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
51068d75effSDimitry Andric     return ScopedInErrorReport::CurrentError().Generic.pc;
51168d75effSDimitry Andric   return 0;
51268d75effSDimitry Andric }
51368d75effSDimitry Andric 
51468d75effSDimitry Andric uptr __asan_get_report_bp() {
51568d75effSDimitry Andric   if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
51668d75effSDimitry Andric     return ScopedInErrorReport::CurrentError().Generic.bp;
51768d75effSDimitry Andric   return 0;
51868d75effSDimitry Andric }
51968d75effSDimitry Andric 
52068d75effSDimitry Andric uptr __asan_get_report_sp() {
52168d75effSDimitry Andric   if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
52268d75effSDimitry Andric     return ScopedInErrorReport::CurrentError().Generic.sp;
52368d75effSDimitry Andric   return 0;
52468d75effSDimitry Andric }
52568d75effSDimitry Andric 
52668d75effSDimitry Andric uptr __asan_get_report_address() {
52768d75effSDimitry Andric   ErrorDescription &err = ScopedInErrorReport::CurrentError();
52868d75effSDimitry Andric   if (err.kind == kErrorKindGeneric)
52968d75effSDimitry Andric     return err.Generic.addr_description.Address();
53068d75effSDimitry Andric   else if (err.kind == kErrorKindDoubleFree)
53168d75effSDimitry Andric     return err.DoubleFree.addr_description.addr;
53268d75effSDimitry Andric   return 0;
53368d75effSDimitry Andric }
53468d75effSDimitry Andric 
53568d75effSDimitry Andric int __asan_get_report_access_type() {
53668d75effSDimitry Andric   if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
53768d75effSDimitry Andric     return ScopedInErrorReport::CurrentError().Generic.is_write;
53868d75effSDimitry Andric   return 0;
53968d75effSDimitry Andric }
54068d75effSDimitry Andric 
54168d75effSDimitry Andric uptr __asan_get_report_access_size() {
54268d75effSDimitry Andric   if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
54368d75effSDimitry Andric     return ScopedInErrorReport::CurrentError().Generic.access_size;
54468d75effSDimitry Andric   return 0;
54568d75effSDimitry Andric }
54668d75effSDimitry Andric 
54768d75effSDimitry Andric const char *__asan_get_report_description() {
54868d75effSDimitry Andric   if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
54968d75effSDimitry Andric     return ScopedInErrorReport::CurrentError().Generic.bug_descr;
55068d75effSDimitry Andric   return ScopedInErrorReport::CurrentError().Base.scariness.GetDescription();
55168d75effSDimitry Andric }
55268d75effSDimitry Andric 
55368d75effSDimitry Andric extern "C" {
55468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
55568d75effSDimitry Andric void __sanitizer_ptr_sub(void *a, void *b) {
55668d75effSDimitry Andric   CheckForInvalidPointerPair(a, b);
55768d75effSDimitry Andric }
55868d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
55968d75effSDimitry Andric void __sanitizer_ptr_cmp(void *a, void *b) {
56068d75effSDimitry Andric   CheckForInvalidPointerPair(a, b);
56168d75effSDimitry Andric }
56268d75effSDimitry Andric } // extern "C"
56368d75effSDimitry Andric 
56468d75effSDimitry Andric // Provide default implementation of __asan_on_error that does nothing
56568d75effSDimitry Andric // and may be overriden by user.
56668d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __asan_on_error, void) {}
567