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 
14*81ad6265SDimitry Andric #include "asan_report.h"
15*81ad6265SDimitry Andric 
16*81ad6265SDimitry 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"
26*81ad6265SDimitry 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 
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 
6068d75effSDimitry Andric void PrintMemoryByte(InternalScopedString *str, const char *before, u8 byte,
6168d75effSDimitry Andric                      bool in_shadow, const char *after) {
6268d75effSDimitry Andric   Decorator d;
6368d75effSDimitry Andric   str->append("%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 
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 
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:
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
35768d75effSDimitry Andric void ReportODRViolation(const __asan_global *g1, u32 stack_id1,
35868d75effSDimitry Andric                         const __asan_global *g2, u32 stack_id2) {
35968d75effSDimitry Andric   ScopedInErrorReport in_report;
36068d75effSDimitry Andric   ErrorODRViolation error(GetCurrentTidOrInvalid(), g1, stack_id1, g2,
36168d75effSDimitry Andric                           stack_id2);
36268d75effSDimitry Andric   in_report.ReportError(error);
36368d75effSDimitry Andric }
36468d75effSDimitry Andric 
36568d75effSDimitry Andric // ----------------------- CheckForInvalidPointerPair ----------- {{{1
36668d75effSDimitry Andric static NOINLINE void ReportInvalidPointerPair(uptr pc, uptr bp, uptr sp,
36768d75effSDimitry Andric                                               uptr a1, uptr a2) {
36868d75effSDimitry Andric   ScopedInErrorReport in_report;
36968d75effSDimitry Andric   ErrorInvalidPointerPair error(GetCurrentTidOrInvalid(), pc, bp, sp, a1, a2);
37068d75effSDimitry Andric   in_report.ReportError(error);
37168d75effSDimitry Andric }
37268d75effSDimitry Andric 
37368d75effSDimitry Andric static bool IsInvalidPointerPair(uptr a1, uptr a2) {
37468d75effSDimitry Andric   if (a1 == a2)
37568d75effSDimitry Andric     return false;
37668d75effSDimitry Andric 
37768d75effSDimitry Andric   // 256B in shadow memory can be iterated quite fast
37868d75effSDimitry Andric   static const uptr kMaxOffset = 2048;
37968d75effSDimitry Andric 
38068d75effSDimitry Andric   uptr left = a1 < a2 ? a1 : a2;
38168d75effSDimitry Andric   uptr right = a1 < a2 ? a2 : a1;
38268d75effSDimitry Andric   uptr offset = right - left;
38368d75effSDimitry Andric   if (offset <= kMaxOffset)
38468d75effSDimitry Andric     return __asan_region_is_poisoned(left, offset);
38568d75effSDimitry Andric 
38668d75effSDimitry Andric   AsanThread *t = GetCurrentThread();
38768d75effSDimitry Andric 
38868d75effSDimitry Andric   // check whether left is a stack memory pointer
38968d75effSDimitry Andric   if (uptr shadow_offset1 = t->GetStackVariableShadowStart(left)) {
39068d75effSDimitry Andric     uptr shadow_offset2 = t->GetStackVariableShadowStart(right);
39168d75effSDimitry Andric     return shadow_offset2 == 0 || shadow_offset1 != shadow_offset2;
39268d75effSDimitry Andric   }
39368d75effSDimitry Andric 
39468d75effSDimitry Andric   // check whether left is a heap memory address
39568d75effSDimitry Andric   HeapAddressDescription hdesc1, hdesc2;
39668d75effSDimitry Andric   if (GetHeapAddressInformation(left, 0, &hdesc1) &&
39768d75effSDimitry Andric       hdesc1.chunk_access.access_type == kAccessTypeInside)
39868d75effSDimitry Andric     return !GetHeapAddressInformation(right, 0, &hdesc2) ||
39968d75effSDimitry Andric         hdesc2.chunk_access.access_type != kAccessTypeInside ||
40068d75effSDimitry Andric         hdesc1.chunk_access.chunk_begin != hdesc2.chunk_access.chunk_begin;
40168d75effSDimitry Andric 
40268d75effSDimitry Andric   // check whether left is an address of a global variable
40368d75effSDimitry Andric   GlobalAddressDescription gdesc1, gdesc2;
40468d75effSDimitry Andric   if (GetGlobalAddressInformation(left, 0, &gdesc1))
40568d75effSDimitry Andric     return !GetGlobalAddressInformation(right - 1, 0, &gdesc2) ||
40668d75effSDimitry Andric         !gdesc1.PointsInsideTheSameVariable(gdesc2);
40768d75effSDimitry Andric 
40868d75effSDimitry Andric   if (t->GetStackVariableShadowStart(right) ||
40968d75effSDimitry Andric       GetHeapAddressInformation(right, 0, &hdesc2) ||
41068d75effSDimitry Andric       GetGlobalAddressInformation(right - 1, 0, &gdesc2))
41168d75effSDimitry Andric     return true;
41268d75effSDimitry Andric 
41368d75effSDimitry Andric   // At this point we know nothing about both a1 and a2 addresses.
41468d75effSDimitry Andric   return false;
41568d75effSDimitry Andric }
41668d75effSDimitry Andric 
417e8d8bef9SDimitry Andric static inline void CheckForInvalidPointerPair(void *p1, void *p2) {
41868d75effSDimitry Andric   switch (flags()->detect_invalid_pointer_pairs) {
41968d75effSDimitry Andric     case 0:
42068d75effSDimitry Andric       return;
42168d75effSDimitry Andric     case 1:
42268d75effSDimitry Andric       if (p1 == nullptr || p2 == nullptr)
42368d75effSDimitry Andric         return;
42468d75effSDimitry Andric       break;
42568d75effSDimitry Andric   }
42668d75effSDimitry Andric 
42768d75effSDimitry Andric   uptr a1 = reinterpret_cast<uptr>(p1);
42868d75effSDimitry Andric   uptr a2 = reinterpret_cast<uptr>(p2);
42968d75effSDimitry Andric 
43068d75effSDimitry Andric   if (IsInvalidPointerPair(a1, a2)) {
43168d75effSDimitry Andric     GET_CALLER_PC_BP_SP;
43268d75effSDimitry Andric     ReportInvalidPointerPair(pc, bp, sp, a1, a2);
43368d75effSDimitry Andric   }
43468d75effSDimitry Andric }
43568d75effSDimitry Andric // ----------------------- Mac-specific reports ----------------- {{{1
43668d75effSDimitry Andric 
43768d75effSDimitry Andric void ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name,
43868d75effSDimitry Andric                                BufferedStackTrace *stack) {
43968d75effSDimitry Andric   ScopedInErrorReport in_report;
440349cc55cSDimitry Andric   Printf(
441349cc55cSDimitry Andric       "mz_realloc(%p) -- attempting to realloc unallocated memory.\n"
44268d75effSDimitry Andric       "This is an unrecoverable problem, exiting now.\n",
443349cc55cSDimitry Andric       (void *)addr);
44468d75effSDimitry Andric   PrintZoneForPointer(addr, zone_ptr, zone_name);
44568d75effSDimitry Andric   stack->Print();
44668d75effSDimitry Andric   DescribeAddressIfHeap(addr);
44768d75effSDimitry Andric }
44868d75effSDimitry Andric 
44968d75effSDimitry Andric // -------------- SuppressErrorReport -------------- {{{1
45068d75effSDimitry Andric // Avoid error reports duplicating for ASan recover mode.
45168d75effSDimitry Andric static bool SuppressErrorReport(uptr pc) {
45268d75effSDimitry Andric   if (!common_flags()->suppress_equal_pcs) return false;
45368d75effSDimitry Andric   for (unsigned i = 0; i < kAsanBuggyPcPoolSize; i++) {
45468d75effSDimitry Andric     uptr cmp = atomic_load_relaxed(&AsanBuggyPcPool[i]);
45568d75effSDimitry Andric     if (cmp == 0 && atomic_compare_exchange_strong(&AsanBuggyPcPool[i], &cmp,
45668d75effSDimitry Andric                                                    pc, memory_order_relaxed))
45768d75effSDimitry Andric       return false;
45868d75effSDimitry Andric     if (cmp == pc) return true;
45968d75effSDimitry Andric   }
46068d75effSDimitry Andric   Die();
46168d75effSDimitry Andric }
46268d75effSDimitry Andric 
46368d75effSDimitry Andric void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write,
46468d75effSDimitry Andric                         uptr access_size, u32 exp, bool fatal) {
4654824e7fdSDimitry Andric   if (__asan_test_only_reported_buggy_pointer) {
4664824e7fdSDimitry Andric     *__asan_test_only_reported_buggy_pointer = addr;
4674824e7fdSDimitry Andric     return;
4684824e7fdSDimitry Andric   }
46968d75effSDimitry Andric   if (!fatal && SuppressErrorReport(pc)) return;
47068d75effSDimitry Andric   ENABLE_FRAME_POINTER;
47168d75effSDimitry Andric 
47268d75effSDimitry Andric   // Optimization experiments.
47368d75effSDimitry Andric   // The experiments can be used to evaluate potential optimizations that remove
47468d75effSDimitry Andric   // instrumentation (assess false negatives). Instead of completely removing
47568d75effSDimitry Andric   // some instrumentation, compiler can emit special calls into runtime
47668d75effSDimitry Andric   // (e.g. __asan_report_exp_load1 instead of __asan_report_load1) and pass
47768d75effSDimitry Andric   // mask of experiments (exp).
47868d75effSDimitry Andric   // The reaction to a non-zero value of exp is to be defined.
47968d75effSDimitry Andric   (void)exp;
48068d75effSDimitry Andric 
48168d75effSDimitry Andric   ScopedInErrorReport in_report(fatal);
48268d75effSDimitry Andric   ErrorGeneric error(GetCurrentTidOrInvalid(), pc, bp, sp, addr, is_write,
48368d75effSDimitry Andric                      access_size);
48468d75effSDimitry Andric   in_report.ReportError(error);
48568d75effSDimitry Andric }
48668d75effSDimitry Andric 
48768d75effSDimitry Andric }  // namespace __asan
48868d75effSDimitry Andric 
48968d75effSDimitry Andric // --------------------------- Interface --------------------- {{{1
49068d75effSDimitry Andric using namespace __asan;
49168d75effSDimitry Andric 
49268d75effSDimitry Andric void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write,
49368d75effSDimitry Andric                          uptr access_size, u32 exp) {
49468d75effSDimitry Andric   ENABLE_FRAME_POINTER;
49568d75effSDimitry Andric   bool fatal = flags()->halt_on_error;
49668d75effSDimitry Andric   ReportGenericError(pc, bp, sp, addr, is_write, access_size, exp, fatal);
49768d75effSDimitry Andric }
49868d75effSDimitry Andric 
49968d75effSDimitry Andric void NOINLINE __asan_set_error_report_callback(void (*callback)(const char*)) {
500349cc55cSDimitry Andric   Lock l(&error_message_buf_mutex);
50168d75effSDimitry Andric   error_report_callback = callback;
50268d75effSDimitry Andric }
50368d75effSDimitry Andric 
50468d75effSDimitry Andric void __asan_describe_address(uptr addr) {
50568d75effSDimitry Andric   // Thread registry must be locked while we're describing an address.
50668d75effSDimitry Andric   asanThreadRegistry().Lock();
50768d75effSDimitry Andric   PrintAddressDescription(addr, 1, "");
50868d75effSDimitry Andric   asanThreadRegistry().Unlock();
50968d75effSDimitry Andric }
51068d75effSDimitry Andric 
51168d75effSDimitry Andric int __asan_report_present() {
51268d75effSDimitry Andric   return ScopedInErrorReport::CurrentError().kind != kErrorKindInvalid;
51368d75effSDimitry Andric }
51468d75effSDimitry Andric 
51568d75effSDimitry Andric uptr __asan_get_report_pc() {
51668d75effSDimitry Andric   if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
51768d75effSDimitry Andric     return ScopedInErrorReport::CurrentError().Generic.pc;
51868d75effSDimitry Andric   return 0;
51968d75effSDimitry Andric }
52068d75effSDimitry Andric 
52168d75effSDimitry Andric uptr __asan_get_report_bp() {
52268d75effSDimitry Andric   if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
52368d75effSDimitry Andric     return ScopedInErrorReport::CurrentError().Generic.bp;
52468d75effSDimitry Andric   return 0;
52568d75effSDimitry Andric }
52668d75effSDimitry Andric 
52768d75effSDimitry Andric uptr __asan_get_report_sp() {
52868d75effSDimitry Andric   if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
52968d75effSDimitry Andric     return ScopedInErrorReport::CurrentError().Generic.sp;
53068d75effSDimitry Andric   return 0;
53168d75effSDimitry Andric }
53268d75effSDimitry Andric 
53368d75effSDimitry Andric uptr __asan_get_report_address() {
53468d75effSDimitry Andric   ErrorDescription &err = ScopedInErrorReport::CurrentError();
53568d75effSDimitry Andric   if (err.kind == kErrorKindGeneric)
53668d75effSDimitry Andric     return err.Generic.addr_description.Address();
53768d75effSDimitry Andric   else if (err.kind == kErrorKindDoubleFree)
53868d75effSDimitry Andric     return err.DoubleFree.addr_description.addr;
53968d75effSDimitry Andric   return 0;
54068d75effSDimitry Andric }
54168d75effSDimitry Andric 
54268d75effSDimitry Andric int __asan_get_report_access_type() {
54368d75effSDimitry Andric   if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
54468d75effSDimitry Andric     return ScopedInErrorReport::CurrentError().Generic.is_write;
54568d75effSDimitry Andric   return 0;
54668d75effSDimitry Andric }
54768d75effSDimitry Andric 
54868d75effSDimitry Andric uptr __asan_get_report_access_size() {
54968d75effSDimitry Andric   if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
55068d75effSDimitry Andric     return ScopedInErrorReport::CurrentError().Generic.access_size;
55168d75effSDimitry Andric   return 0;
55268d75effSDimitry Andric }
55368d75effSDimitry Andric 
55468d75effSDimitry Andric const char *__asan_get_report_description() {
55568d75effSDimitry Andric   if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
55668d75effSDimitry Andric     return ScopedInErrorReport::CurrentError().Generic.bug_descr;
55768d75effSDimitry Andric   return ScopedInErrorReport::CurrentError().Base.scariness.GetDescription();
55868d75effSDimitry Andric }
55968d75effSDimitry Andric 
56068d75effSDimitry Andric extern "C" {
56168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
56268d75effSDimitry Andric void __sanitizer_ptr_sub(void *a, void *b) {
56368d75effSDimitry Andric   CheckForInvalidPointerPair(a, b);
56468d75effSDimitry Andric }
56568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
56668d75effSDimitry Andric void __sanitizer_ptr_cmp(void *a, void *b) {
56768d75effSDimitry Andric   CheckForInvalidPointerPair(a, b);
56868d75effSDimitry Andric }
56968d75effSDimitry Andric } // extern "C"
57068d75effSDimitry Andric 
57168d75effSDimitry Andric // Provide default implementation of __asan_on_error that does nothing
57268d75effSDimitry Andric // and may be overriden by user.
57368d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __asan_on_error, void) {}
574