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