1*68d75effSDimitry Andric //===-- asan_report.cpp ---------------------------------------------------===// 2*68d75effSDimitry Andric // 3*68d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*68d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*68d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*68d75effSDimitry Andric // 7*68d75effSDimitry Andric //===----------------------------------------------------------------------===// 8*68d75effSDimitry Andric // 9*68d75effSDimitry Andric // This file is a part of AddressSanitizer, an address sanity checker. 10*68d75effSDimitry Andric // 11*68d75effSDimitry Andric // This file contains error reporting code. 12*68d75effSDimitry Andric //===----------------------------------------------------------------------===// 13*68d75effSDimitry Andric 14*68d75effSDimitry Andric #include "asan_errors.h" 15*68d75effSDimitry Andric #include "asan_flags.h" 16*68d75effSDimitry Andric #include "asan_descriptions.h" 17*68d75effSDimitry Andric #include "asan_internal.h" 18*68d75effSDimitry Andric #include "asan_mapping.h" 19*68d75effSDimitry Andric #include "asan_report.h" 20*68d75effSDimitry Andric #include "asan_scariness_score.h" 21*68d75effSDimitry Andric #include "asan_stack.h" 22*68d75effSDimitry Andric #include "asan_thread.h" 23*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_common.h" 24*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_flags.h" 25*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_report_decorator.h" 26*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_stackdepot.h" 27*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_symbolizer.h" 28*68d75effSDimitry Andric 29*68d75effSDimitry Andric namespace __asan { 30*68d75effSDimitry Andric 31*68d75effSDimitry Andric // -------------------- User-specified callbacks ----------------- {{{1 32*68d75effSDimitry Andric static void (*error_report_callback)(const char*); 33*68d75effSDimitry Andric static char *error_message_buffer = nullptr; 34*68d75effSDimitry Andric static uptr error_message_buffer_pos = 0; 35*68d75effSDimitry Andric static BlockingMutex error_message_buf_mutex(LINKER_INITIALIZED); 36*68d75effSDimitry Andric static const unsigned kAsanBuggyPcPoolSize = 25; 37*68d75effSDimitry Andric static __sanitizer::atomic_uintptr_t AsanBuggyPcPool[kAsanBuggyPcPoolSize]; 38*68d75effSDimitry Andric 39*68d75effSDimitry Andric void AppendToErrorMessageBuffer(const char *buffer) { 40*68d75effSDimitry Andric BlockingMutexLock l(&error_message_buf_mutex); 41*68d75effSDimitry Andric if (!error_message_buffer) { 42*68d75effSDimitry Andric error_message_buffer = 43*68d75effSDimitry Andric (char*)MmapOrDieQuietly(kErrorMessageBufferSize, __func__); 44*68d75effSDimitry Andric error_message_buffer_pos = 0; 45*68d75effSDimitry Andric } 46*68d75effSDimitry Andric uptr length = internal_strlen(buffer); 47*68d75effSDimitry Andric RAW_CHECK(kErrorMessageBufferSize >= error_message_buffer_pos); 48*68d75effSDimitry Andric uptr remaining = kErrorMessageBufferSize - error_message_buffer_pos; 49*68d75effSDimitry Andric internal_strncpy(error_message_buffer + error_message_buffer_pos, 50*68d75effSDimitry Andric buffer, remaining); 51*68d75effSDimitry Andric error_message_buffer[kErrorMessageBufferSize - 1] = '\0'; 52*68d75effSDimitry Andric // FIXME: reallocate the buffer instead of truncating the message. 53*68d75effSDimitry Andric error_message_buffer_pos += Min(remaining, length); 54*68d75effSDimitry Andric } 55*68d75effSDimitry Andric 56*68d75effSDimitry Andric // ---------------------- Helper functions ----------------------- {{{1 57*68d75effSDimitry Andric 58*68d75effSDimitry Andric void PrintMemoryByte(InternalScopedString *str, const char *before, u8 byte, 59*68d75effSDimitry Andric bool in_shadow, const char *after) { 60*68d75effSDimitry Andric Decorator d; 61*68d75effSDimitry Andric str->append("%s%s%x%x%s%s", before, 62*68d75effSDimitry Andric in_shadow ? d.ShadowByte(byte) : d.MemoryByte(), byte >> 4, 63*68d75effSDimitry Andric byte & 15, d.Default(), after); 64*68d75effSDimitry Andric } 65*68d75effSDimitry Andric 66*68d75effSDimitry Andric static void PrintZoneForPointer(uptr ptr, uptr zone_ptr, 67*68d75effSDimitry Andric const char *zone_name) { 68*68d75effSDimitry Andric if (zone_ptr) { 69*68d75effSDimitry Andric if (zone_name) { 70*68d75effSDimitry Andric Printf("malloc_zone_from_ptr(%p) = %p, which is %s\n", 71*68d75effSDimitry Andric ptr, zone_ptr, zone_name); 72*68d75effSDimitry Andric } else { 73*68d75effSDimitry Andric Printf("malloc_zone_from_ptr(%p) = %p, which doesn't have a name\n", 74*68d75effSDimitry Andric ptr, zone_ptr); 75*68d75effSDimitry Andric } 76*68d75effSDimitry Andric } else { 77*68d75effSDimitry Andric Printf("malloc_zone_from_ptr(%p) = 0\n", ptr); 78*68d75effSDimitry Andric } 79*68d75effSDimitry Andric } 80*68d75effSDimitry Andric 81*68d75effSDimitry Andric // ---------------------- Address Descriptions ------------------- {{{1 82*68d75effSDimitry Andric 83*68d75effSDimitry Andric bool ParseFrameDescription(const char *frame_descr, 84*68d75effSDimitry Andric InternalMmapVector<StackVarDescr> *vars) { 85*68d75effSDimitry Andric CHECK(frame_descr); 86*68d75effSDimitry Andric const char *p; 87*68d75effSDimitry Andric // This string is created by the compiler and has the following form: 88*68d75effSDimitry Andric // "n alloc_1 alloc_2 ... alloc_n" 89*68d75effSDimitry Andric // where alloc_i looks like "offset size len ObjectName" 90*68d75effSDimitry Andric // or "offset size len ObjectName:line". 91*68d75effSDimitry Andric uptr n_objects = (uptr)internal_simple_strtoll(frame_descr, &p, 10); 92*68d75effSDimitry Andric if (n_objects == 0) 93*68d75effSDimitry Andric return false; 94*68d75effSDimitry Andric 95*68d75effSDimitry Andric for (uptr i = 0; i < n_objects; i++) { 96*68d75effSDimitry Andric uptr beg = (uptr)internal_simple_strtoll(p, &p, 10); 97*68d75effSDimitry Andric uptr size = (uptr)internal_simple_strtoll(p, &p, 10); 98*68d75effSDimitry Andric uptr len = (uptr)internal_simple_strtoll(p, &p, 10); 99*68d75effSDimitry Andric if (beg == 0 || size == 0 || *p != ' ') { 100*68d75effSDimitry Andric return false; 101*68d75effSDimitry Andric } 102*68d75effSDimitry Andric p++; 103*68d75effSDimitry Andric char *colon_pos = internal_strchr(p, ':'); 104*68d75effSDimitry Andric uptr line = 0; 105*68d75effSDimitry Andric uptr name_len = len; 106*68d75effSDimitry Andric if (colon_pos != nullptr && colon_pos < p + len) { 107*68d75effSDimitry Andric name_len = colon_pos - p; 108*68d75effSDimitry Andric line = (uptr)internal_simple_strtoll(colon_pos + 1, nullptr, 10); 109*68d75effSDimitry Andric } 110*68d75effSDimitry Andric StackVarDescr var = {beg, size, p, name_len, line}; 111*68d75effSDimitry Andric vars->push_back(var); 112*68d75effSDimitry Andric p += len; 113*68d75effSDimitry Andric } 114*68d75effSDimitry Andric 115*68d75effSDimitry Andric return true; 116*68d75effSDimitry Andric } 117*68d75effSDimitry Andric 118*68d75effSDimitry Andric // -------------------- Different kinds of reports ----------------- {{{1 119*68d75effSDimitry Andric 120*68d75effSDimitry Andric // Use ScopedInErrorReport to run common actions just before and 121*68d75effSDimitry Andric // immediately after printing error report. 122*68d75effSDimitry Andric class ScopedInErrorReport { 123*68d75effSDimitry Andric public: 124*68d75effSDimitry Andric explicit ScopedInErrorReport(bool fatal = false) 125*68d75effSDimitry Andric : halt_on_error_(fatal || flags()->halt_on_error) { 126*68d75effSDimitry Andric // Make sure the registry and sanitizer report mutexes are locked while 127*68d75effSDimitry Andric // we're printing an error report. 128*68d75effSDimitry Andric // We can lock them only here to avoid self-deadlock in case of 129*68d75effSDimitry Andric // recursive reports. 130*68d75effSDimitry Andric asanThreadRegistry().Lock(); 131*68d75effSDimitry Andric Printf( 132*68d75effSDimitry Andric "=================================================================\n"); 133*68d75effSDimitry Andric } 134*68d75effSDimitry Andric 135*68d75effSDimitry Andric ~ScopedInErrorReport() { 136*68d75effSDimitry Andric if (halt_on_error_ && !__sanitizer_acquire_crash_state()) { 137*68d75effSDimitry Andric asanThreadRegistry().Unlock(); 138*68d75effSDimitry Andric return; 139*68d75effSDimitry Andric } 140*68d75effSDimitry Andric ASAN_ON_ERROR(); 141*68d75effSDimitry Andric if (current_error_.IsValid()) current_error_.Print(); 142*68d75effSDimitry Andric 143*68d75effSDimitry Andric // Make sure the current thread is announced. 144*68d75effSDimitry Andric DescribeThread(GetCurrentThread()); 145*68d75effSDimitry Andric // We may want to grab this lock again when printing stats. 146*68d75effSDimitry Andric asanThreadRegistry().Unlock(); 147*68d75effSDimitry Andric // Print memory stats. 148*68d75effSDimitry Andric if (flags()->print_stats) 149*68d75effSDimitry Andric __asan_print_accumulated_stats(); 150*68d75effSDimitry Andric 151*68d75effSDimitry Andric if (common_flags()->print_cmdline) 152*68d75effSDimitry Andric PrintCmdline(); 153*68d75effSDimitry Andric 154*68d75effSDimitry Andric if (common_flags()->print_module_map == 2) PrintModuleMap(); 155*68d75effSDimitry Andric 156*68d75effSDimitry Andric // Copy the message buffer so that we could start logging without holding a 157*68d75effSDimitry Andric // lock that gets aquired during printing. 158*68d75effSDimitry Andric InternalMmapVector<char> buffer_copy(kErrorMessageBufferSize); 159*68d75effSDimitry Andric { 160*68d75effSDimitry Andric BlockingMutexLock l(&error_message_buf_mutex); 161*68d75effSDimitry Andric internal_memcpy(buffer_copy.data(), 162*68d75effSDimitry Andric error_message_buffer, kErrorMessageBufferSize); 163*68d75effSDimitry Andric } 164*68d75effSDimitry Andric 165*68d75effSDimitry Andric LogFullErrorReport(buffer_copy.data()); 166*68d75effSDimitry Andric 167*68d75effSDimitry Andric if (error_report_callback) { 168*68d75effSDimitry Andric error_report_callback(buffer_copy.data()); 169*68d75effSDimitry Andric } 170*68d75effSDimitry Andric 171*68d75effSDimitry Andric if (halt_on_error_ && common_flags()->abort_on_error) { 172*68d75effSDimitry Andric // On Android the message is truncated to 512 characters. 173*68d75effSDimitry Andric // FIXME: implement "compact" error format, possibly without, or with 174*68d75effSDimitry Andric // highly compressed stack traces? 175*68d75effSDimitry Andric // FIXME: or just use the summary line as abort message? 176*68d75effSDimitry Andric SetAbortMessage(buffer_copy.data()); 177*68d75effSDimitry Andric } 178*68d75effSDimitry Andric 179*68d75effSDimitry Andric // In halt_on_error = false mode, reset the current error object (before 180*68d75effSDimitry Andric // unlocking). 181*68d75effSDimitry Andric if (!halt_on_error_) 182*68d75effSDimitry Andric internal_memset(¤t_error_, 0, sizeof(current_error_)); 183*68d75effSDimitry Andric 184*68d75effSDimitry Andric if (halt_on_error_) { 185*68d75effSDimitry Andric Report("ABORTING\n"); 186*68d75effSDimitry Andric Die(); 187*68d75effSDimitry Andric } 188*68d75effSDimitry Andric } 189*68d75effSDimitry Andric 190*68d75effSDimitry Andric void ReportError(const ErrorDescription &description) { 191*68d75effSDimitry Andric // Can only report one error per ScopedInErrorReport. 192*68d75effSDimitry Andric CHECK_EQ(current_error_.kind, kErrorKindInvalid); 193*68d75effSDimitry Andric internal_memcpy(¤t_error_, &description, sizeof(current_error_)); 194*68d75effSDimitry Andric } 195*68d75effSDimitry Andric 196*68d75effSDimitry Andric static ErrorDescription &CurrentError() { 197*68d75effSDimitry Andric return current_error_; 198*68d75effSDimitry Andric } 199*68d75effSDimitry Andric 200*68d75effSDimitry Andric private: 201*68d75effSDimitry Andric ScopedErrorReportLock error_report_lock_; 202*68d75effSDimitry Andric // Error currently being reported. This enables the destructor to interact 203*68d75effSDimitry Andric // with the debugger and point it to an error description. 204*68d75effSDimitry Andric static ErrorDescription current_error_; 205*68d75effSDimitry Andric bool halt_on_error_; 206*68d75effSDimitry Andric }; 207*68d75effSDimitry Andric 208*68d75effSDimitry Andric ErrorDescription ScopedInErrorReport::current_error_(LINKER_INITIALIZED); 209*68d75effSDimitry Andric 210*68d75effSDimitry Andric void ReportDeadlySignal(const SignalContext &sig) { 211*68d75effSDimitry Andric ScopedInErrorReport in_report(/*fatal*/ true); 212*68d75effSDimitry Andric ErrorDeadlySignal error(GetCurrentTidOrInvalid(), sig); 213*68d75effSDimitry Andric in_report.ReportError(error); 214*68d75effSDimitry Andric } 215*68d75effSDimitry Andric 216*68d75effSDimitry Andric void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack) { 217*68d75effSDimitry Andric ScopedInErrorReport in_report; 218*68d75effSDimitry Andric ErrorDoubleFree error(GetCurrentTidOrInvalid(), free_stack, addr); 219*68d75effSDimitry Andric in_report.ReportError(error); 220*68d75effSDimitry Andric } 221*68d75effSDimitry Andric 222*68d75effSDimitry Andric void ReportNewDeleteTypeMismatch(uptr addr, uptr delete_size, 223*68d75effSDimitry Andric uptr delete_alignment, 224*68d75effSDimitry Andric BufferedStackTrace *free_stack) { 225*68d75effSDimitry Andric ScopedInErrorReport in_report; 226*68d75effSDimitry Andric ErrorNewDeleteTypeMismatch error(GetCurrentTidOrInvalid(), free_stack, addr, 227*68d75effSDimitry Andric delete_size, delete_alignment); 228*68d75effSDimitry Andric in_report.ReportError(error); 229*68d75effSDimitry Andric } 230*68d75effSDimitry Andric 231*68d75effSDimitry Andric void ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack) { 232*68d75effSDimitry Andric ScopedInErrorReport in_report; 233*68d75effSDimitry Andric ErrorFreeNotMalloced error(GetCurrentTidOrInvalid(), free_stack, addr); 234*68d75effSDimitry Andric in_report.ReportError(error); 235*68d75effSDimitry Andric } 236*68d75effSDimitry Andric 237*68d75effSDimitry Andric void ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack, 238*68d75effSDimitry Andric AllocType alloc_type, 239*68d75effSDimitry Andric AllocType dealloc_type) { 240*68d75effSDimitry Andric ScopedInErrorReport in_report; 241*68d75effSDimitry Andric ErrorAllocTypeMismatch error(GetCurrentTidOrInvalid(), free_stack, addr, 242*68d75effSDimitry Andric alloc_type, dealloc_type); 243*68d75effSDimitry Andric in_report.ReportError(error); 244*68d75effSDimitry Andric } 245*68d75effSDimitry Andric 246*68d75effSDimitry Andric void ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack) { 247*68d75effSDimitry Andric ScopedInErrorReport in_report; 248*68d75effSDimitry Andric ErrorMallocUsableSizeNotOwned error(GetCurrentTidOrInvalid(), stack, addr); 249*68d75effSDimitry Andric in_report.ReportError(error); 250*68d75effSDimitry Andric } 251*68d75effSDimitry Andric 252*68d75effSDimitry Andric void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr, 253*68d75effSDimitry Andric BufferedStackTrace *stack) { 254*68d75effSDimitry Andric ScopedInErrorReport in_report; 255*68d75effSDimitry Andric ErrorSanitizerGetAllocatedSizeNotOwned error(GetCurrentTidOrInvalid(), stack, 256*68d75effSDimitry Andric addr); 257*68d75effSDimitry Andric in_report.ReportError(error); 258*68d75effSDimitry Andric } 259*68d75effSDimitry Andric 260*68d75effSDimitry Andric void ReportCallocOverflow(uptr count, uptr size, BufferedStackTrace *stack) { 261*68d75effSDimitry Andric ScopedInErrorReport in_report(/*fatal*/ true); 262*68d75effSDimitry Andric ErrorCallocOverflow error(GetCurrentTidOrInvalid(), stack, count, size); 263*68d75effSDimitry Andric in_report.ReportError(error); 264*68d75effSDimitry Andric } 265*68d75effSDimitry Andric 266*68d75effSDimitry Andric void ReportReallocArrayOverflow(uptr count, uptr size, 267*68d75effSDimitry Andric BufferedStackTrace *stack) { 268*68d75effSDimitry Andric ScopedInErrorReport in_report(/*fatal*/ true); 269*68d75effSDimitry Andric ErrorReallocArrayOverflow error(GetCurrentTidOrInvalid(), stack, count, size); 270*68d75effSDimitry Andric in_report.ReportError(error); 271*68d75effSDimitry Andric } 272*68d75effSDimitry Andric 273*68d75effSDimitry Andric void ReportPvallocOverflow(uptr size, BufferedStackTrace *stack) { 274*68d75effSDimitry Andric ScopedInErrorReport in_report(/*fatal*/ true); 275*68d75effSDimitry Andric ErrorPvallocOverflow error(GetCurrentTidOrInvalid(), stack, size); 276*68d75effSDimitry Andric in_report.ReportError(error); 277*68d75effSDimitry Andric } 278*68d75effSDimitry Andric 279*68d75effSDimitry Andric void ReportInvalidAllocationAlignment(uptr alignment, 280*68d75effSDimitry Andric BufferedStackTrace *stack) { 281*68d75effSDimitry Andric ScopedInErrorReport in_report(/*fatal*/ true); 282*68d75effSDimitry Andric ErrorInvalidAllocationAlignment error(GetCurrentTidOrInvalid(), stack, 283*68d75effSDimitry Andric alignment); 284*68d75effSDimitry Andric in_report.ReportError(error); 285*68d75effSDimitry Andric } 286*68d75effSDimitry Andric 287*68d75effSDimitry Andric void ReportInvalidAlignedAllocAlignment(uptr size, uptr alignment, 288*68d75effSDimitry Andric BufferedStackTrace *stack) { 289*68d75effSDimitry Andric ScopedInErrorReport in_report(/*fatal*/ true); 290*68d75effSDimitry Andric ErrorInvalidAlignedAllocAlignment error(GetCurrentTidOrInvalid(), stack, 291*68d75effSDimitry Andric size, alignment); 292*68d75effSDimitry Andric in_report.ReportError(error); 293*68d75effSDimitry Andric } 294*68d75effSDimitry Andric 295*68d75effSDimitry Andric void ReportInvalidPosixMemalignAlignment(uptr alignment, 296*68d75effSDimitry Andric BufferedStackTrace *stack) { 297*68d75effSDimitry Andric ScopedInErrorReport in_report(/*fatal*/ true); 298*68d75effSDimitry Andric ErrorInvalidPosixMemalignAlignment error(GetCurrentTidOrInvalid(), stack, 299*68d75effSDimitry Andric alignment); 300*68d75effSDimitry Andric in_report.ReportError(error); 301*68d75effSDimitry Andric } 302*68d75effSDimitry Andric 303*68d75effSDimitry Andric void ReportAllocationSizeTooBig(uptr user_size, uptr total_size, uptr max_size, 304*68d75effSDimitry Andric BufferedStackTrace *stack) { 305*68d75effSDimitry Andric ScopedInErrorReport in_report(/*fatal*/ true); 306*68d75effSDimitry Andric ErrorAllocationSizeTooBig error(GetCurrentTidOrInvalid(), stack, user_size, 307*68d75effSDimitry Andric total_size, max_size); 308*68d75effSDimitry Andric in_report.ReportError(error); 309*68d75effSDimitry Andric } 310*68d75effSDimitry Andric 311*68d75effSDimitry Andric void ReportRssLimitExceeded(BufferedStackTrace *stack) { 312*68d75effSDimitry Andric ScopedInErrorReport in_report(/*fatal*/ true); 313*68d75effSDimitry Andric ErrorRssLimitExceeded error(GetCurrentTidOrInvalid(), stack); 314*68d75effSDimitry Andric in_report.ReportError(error); 315*68d75effSDimitry Andric } 316*68d75effSDimitry Andric 317*68d75effSDimitry Andric void ReportOutOfMemory(uptr requested_size, BufferedStackTrace *stack) { 318*68d75effSDimitry Andric ScopedInErrorReport in_report(/*fatal*/ true); 319*68d75effSDimitry Andric ErrorOutOfMemory error(GetCurrentTidOrInvalid(), stack, requested_size); 320*68d75effSDimitry Andric in_report.ReportError(error); 321*68d75effSDimitry Andric } 322*68d75effSDimitry Andric 323*68d75effSDimitry Andric void ReportStringFunctionMemoryRangesOverlap(const char *function, 324*68d75effSDimitry Andric const char *offset1, uptr length1, 325*68d75effSDimitry Andric const char *offset2, uptr length2, 326*68d75effSDimitry Andric BufferedStackTrace *stack) { 327*68d75effSDimitry Andric ScopedInErrorReport in_report; 328*68d75effSDimitry Andric ErrorStringFunctionMemoryRangesOverlap error( 329*68d75effSDimitry Andric GetCurrentTidOrInvalid(), stack, (uptr)offset1, length1, (uptr)offset2, 330*68d75effSDimitry Andric length2, function); 331*68d75effSDimitry Andric in_report.ReportError(error); 332*68d75effSDimitry Andric } 333*68d75effSDimitry Andric 334*68d75effSDimitry Andric void ReportStringFunctionSizeOverflow(uptr offset, uptr size, 335*68d75effSDimitry Andric BufferedStackTrace *stack) { 336*68d75effSDimitry Andric ScopedInErrorReport in_report; 337*68d75effSDimitry Andric ErrorStringFunctionSizeOverflow error(GetCurrentTidOrInvalid(), stack, offset, 338*68d75effSDimitry Andric size); 339*68d75effSDimitry Andric in_report.ReportError(error); 340*68d75effSDimitry Andric } 341*68d75effSDimitry Andric 342*68d75effSDimitry Andric void ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end, 343*68d75effSDimitry Andric uptr old_mid, uptr new_mid, 344*68d75effSDimitry Andric BufferedStackTrace *stack) { 345*68d75effSDimitry Andric ScopedInErrorReport in_report; 346*68d75effSDimitry Andric ErrorBadParamsToAnnotateContiguousContainer error( 347*68d75effSDimitry Andric GetCurrentTidOrInvalid(), stack, beg, end, old_mid, new_mid); 348*68d75effSDimitry Andric in_report.ReportError(error); 349*68d75effSDimitry Andric } 350*68d75effSDimitry Andric 351*68d75effSDimitry Andric void ReportODRViolation(const __asan_global *g1, u32 stack_id1, 352*68d75effSDimitry Andric const __asan_global *g2, u32 stack_id2) { 353*68d75effSDimitry Andric ScopedInErrorReport in_report; 354*68d75effSDimitry Andric ErrorODRViolation error(GetCurrentTidOrInvalid(), g1, stack_id1, g2, 355*68d75effSDimitry Andric stack_id2); 356*68d75effSDimitry Andric in_report.ReportError(error); 357*68d75effSDimitry Andric } 358*68d75effSDimitry Andric 359*68d75effSDimitry Andric // ----------------------- CheckForInvalidPointerPair ----------- {{{1 360*68d75effSDimitry Andric static NOINLINE void ReportInvalidPointerPair(uptr pc, uptr bp, uptr sp, 361*68d75effSDimitry Andric uptr a1, uptr a2) { 362*68d75effSDimitry Andric ScopedInErrorReport in_report; 363*68d75effSDimitry Andric ErrorInvalidPointerPair error(GetCurrentTidOrInvalid(), pc, bp, sp, a1, a2); 364*68d75effSDimitry Andric in_report.ReportError(error); 365*68d75effSDimitry Andric } 366*68d75effSDimitry Andric 367*68d75effSDimitry Andric static bool IsInvalidPointerPair(uptr a1, uptr a2) { 368*68d75effSDimitry Andric if (a1 == a2) 369*68d75effSDimitry Andric return false; 370*68d75effSDimitry Andric 371*68d75effSDimitry Andric // 256B in shadow memory can be iterated quite fast 372*68d75effSDimitry Andric static const uptr kMaxOffset = 2048; 373*68d75effSDimitry Andric 374*68d75effSDimitry Andric uptr left = a1 < a2 ? a1 : a2; 375*68d75effSDimitry Andric uptr right = a1 < a2 ? a2 : a1; 376*68d75effSDimitry Andric uptr offset = right - left; 377*68d75effSDimitry Andric if (offset <= kMaxOffset) 378*68d75effSDimitry Andric return __asan_region_is_poisoned(left, offset); 379*68d75effSDimitry Andric 380*68d75effSDimitry Andric AsanThread *t = GetCurrentThread(); 381*68d75effSDimitry Andric 382*68d75effSDimitry Andric // check whether left is a stack memory pointer 383*68d75effSDimitry Andric if (uptr shadow_offset1 = t->GetStackVariableShadowStart(left)) { 384*68d75effSDimitry Andric uptr shadow_offset2 = t->GetStackVariableShadowStart(right); 385*68d75effSDimitry Andric return shadow_offset2 == 0 || shadow_offset1 != shadow_offset2; 386*68d75effSDimitry Andric } 387*68d75effSDimitry Andric 388*68d75effSDimitry Andric // check whether left is a heap memory address 389*68d75effSDimitry Andric HeapAddressDescription hdesc1, hdesc2; 390*68d75effSDimitry Andric if (GetHeapAddressInformation(left, 0, &hdesc1) && 391*68d75effSDimitry Andric hdesc1.chunk_access.access_type == kAccessTypeInside) 392*68d75effSDimitry Andric return !GetHeapAddressInformation(right, 0, &hdesc2) || 393*68d75effSDimitry Andric hdesc2.chunk_access.access_type != kAccessTypeInside || 394*68d75effSDimitry Andric hdesc1.chunk_access.chunk_begin != hdesc2.chunk_access.chunk_begin; 395*68d75effSDimitry Andric 396*68d75effSDimitry Andric // check whether left is an address of a global variable 397*68d75effSDimitry Andric GlobalAddressDescription gdesc1, gdesc2; 398*68d75effSDimitry Andric if (GetGlobalAddressInformation(left, 0, &gdesc1)) 399*68d75effSDimitry Andric return !GetGlobalAddressInformation(right - 1, 0, &gdesc2) || 400*68d75effSDimitry Andric !gdesc1.PointsInsideTheSameVariable(gdesc2); 401*68d75effSDimitry Andric 402*68d75effSDimitry Andric if (t->GetStackVariableShadowStart(right) || 403*68d75effSDimitry Andric GetHeapAddressInformation(right, 0, &hdesc2) || 404*68d75effSDimitry Andric GetGlobalAddressInformation(right - 1, 0, &gdesc2)) 405*68d75effSDimitry Andric return true; 406*68d75effSDimitry Andric 407*68d75effSDimitry Andric // At this point we know nothing about both a1 and a2 addresses. 408*68d75effSDimitry Andric return false; 409*68d75effSDimitry Andric } 410*68d75effSDimitry Andric 411*68d75effSDimitry Andric static INLINE void CheckForInvalidPointerPair(void *p1, void *p2) { 412*68d75effSDimitry Andric switch (flags()->detect_invalid_pointer_pairs) { 413*68d75effSDimitry Andric case 0: 414*68d75effSDimitry Andric return; 415*68d75effSDimitry Andric case 1: 416*68d75effSDimitry Andric if (p1 == nullptr || p2 == nullptr) 417*68d75effSDimitry Andric return; 418*68d75effSDimitry Andric break; 419*68d75effSDimitry Andric } 420*68d75effSDimitry Andric 421*68d75effSDimitry Andric uptr a1 = reinterpret_cast<uptr>(p1); 422*68d75effSDimitry Andric uptr a2 = reinterpret_cast<uptr>(p2); 423*68d75effSDimitry Andric 424*68d75effSDimitry Andric if (IsInvalidPointerPair(a1, a2)) { 425*68d75effSDimitry Andric GET_CALLER_PC_BP_SP; 426*68d75effSDimitry Andric ReportInvalidPointerPair(pc, bp, sp, a1, a2); 427*68d75effSDimitry Andric } 428*68d75effSDimitry Andric } 429*68d75effSDimitry Andric // ----------------------- Mac-specific reports ----------------- {{{1 430*68d75effSDimitry Andric 431*68d75effSDimitry Andric void ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name, 432*68d75effSDimitry Andric BufferedStackTrace *stack) { 433*68d75effSDimitry Andric ScopedInErrorReport in_report; 434*68d75effSDimitry Andric Printf("mz_realloc(%p) -- attempting to realloc unallocated memory.\n" 435*68d75effSDimitry Andric "This is an unrecoverable problem, exiting now.\n", 436*68d75effSDimitry Andric addr); 437*68d75effSDimitry Andric PrintZoneForPointer(addr, zone_ptr, zone_name); 438*68d75effSDimitry Andric stack->Print(); 439*68d75effSDimitry Andric DescribeAddressIfHeap(addr); 440*68d75effSDimitry Andric } 441*68d75effSDimitry Andric 442*68d75effSDimitry Andric // -------------- SuppressErrorReport -------------- {{{1 443*68d75effSDimitry Andric // Avoid error reports duplicating for ASan recover mode. 444*68d75effSDimitry Andric static bool SuppressErrorReport(uptr pc) { 445*68d75effSDimitry Andric if (!common_flags()->suppress_equal_pcs) return false; 446*68d75effSDimitry Andric for (unsigned i = 0; i < kAsanBuggyPcPoolSize; i++) { 447*68d75effSDimitry Andric uptr cmp = atomic_load_relaxed(&AsanBuggyPcPool[i]); 448*68d75effSDimitry Andric if (cmp == 0 && atomic_compare_exchange_strong(&AsanBuggyPcPool[i], &cmp, 449*68d75effSDimitry Andric pc, memory_order_relaxed)) 450*68d75effSDimitry Andric return false; 451*68d75effSDimitry Andric if (cmp == pc) return true; 452*68d75effSDimitry Andric } 453*68d75effSDimitry Andric Die(); 454*68d75effSDimitry Andric } 455*68d75effSDimitry Andric 456*68d75effSDimitry Andric void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write, 457*68d75effSDimitry Andric uptr access_size, u32 exp, bool fatal) { 458*68d75effSDimitry Andric if (!fatal && SuppressErrorReport(pc)) return; 459*68d75effSDimitry Andric ENABLE_FRAME_POINTER; 460*68d75effSDimitry Andric 461*68d75effSDimitry Andric // Optimization experiments. 462*68d75effSDimitry Andric // The experiments can be used to evaluate potential optimizations that remove 463*68d75effSDimitry Andric // instrumentation (assess false negatives). Instead of completely removing 464*68d75effSDimitry Andric // some instrumentation, compiler can emit special calls into runtime 465*68d75effSDimitry Andric // (e.g. __asan_report_exp_load1 instead of __asan_report_load1) and pass 466*68d75effSDimitry Andric // mask of experiments (exp). 467*68d75effSDimitry Andric // The reaction to a non-zero value of exp is to be defined. 468*68d75effSDimitry Andric (void)exp; 469*68d75effSDimitry Andric 470*68d75effSDimitry Andric ScopedInErrorReport in_report(fatal); 471*68d75effSDimitry Andric ErrorGeneric error(GetCurrentTidOrInvalid(), pc, bp, sp, addr, is_write, 472*68d75effSDimitry Andric access_size); 473*68d75effSDimitry Andric in_report.ReportError(error); 474*68d75effSDimitry Andric } 475*68d75effSDimitry Andric 476*68d75effSDimitry Andric } // namespace __asan 477*68d75effSDimitry Andric 478*68d75effSDimitry Andric // --------------------------- Interface --------------------- {{{1 479*68d75effSDimitry Andric using namespace __asan; 480*68d75effSDimitry Andric 481*68d75effSDimitry Andric void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write, 482*68d75effSDimitry Andric uptr access_size, u32 exp) { 483*68d75effSDimitry Andric ENABLE_FRAME_POINTER; 484*68d75effSDimitry Andric bool fatal = flags()->halt_on_error; 485*68d75effSDimitry Andric ReportGenericError(pc, bp, sp, addr, is_write, access_size, exp, fatal); 486*68d75effSDimitry Andric } 487*68d75effSDimitry Andric 488*68d75effSDimitry Andric void NOINLINE __asan_set_error_report_callback(void (*callback)(const char*)) { 489*68d75effSDimitry Andric BlockingMutexLock l(&error_message_buf_mutex); 490*68d75effSDimitry Andric error_report_callback = callback; 491*68d75effSDimitry Andric } 492*68d75effSDimitry Andric 493*68d75effSDimitry Andric void __asan_describe_address(uptr addr) { 494*68d75effSDimitry Andric // Thread registry must be locked while we're describing an address. 495*68d75effSDimitry Andric asanThreadRegistry().Lock(); 496*68d75effSDimitry Andric PrintAddressDescription(addr, 1, ""); 497*68d75effSDimitry Andric asanThreadRegistry().Unlock(); 498*68d75effSDimitry Andric } 499*68d75effSDimitry Andric 500*68d75effSDimitry Andric int __asan_report_present() { 501*68d75effSDimitry Andric return ScopedInErrorReport::CurrentError().kind != kErrorKindInvalid; 502*68d75effSDimitry Andric } 503*68d75effSDimitry Andric 504*68d75effSDimitry Andric uptr __asan_get_report_pc() { 505*68d75effSDimitry Andric if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric) 506*68d75effSDimitry Andric return ScopedInErrorReport::CurrentError().Generic.pc; 507*68d75effSDimitry Andric return 0; 508*68d75effSDimitry Andric } 509*68d75effSDimitry Andric 510*68d75effSDimitry Andric uptr __asan_get_report_bp() { 511*68d75effSDimitry Andric if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric) 512*68d75effSDimitry Andric return ScopedInErrorReport::CurrentError().Generic.bp; 513*68d75effSDimitry Andric return 0; 514*68d75effSDimitry Andric } 515*68d75effSDimitry Andric 516*68d75effSDimitry Andric uptr __asan_get_report_sp() { 517*68d75effSDimitry Andric if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric) 518*68d75effSDimitry Andric return ScopedInErrorReport::CurrentError().Generic.sp; 519*68d75effSDimitry Andric return 0; 520*68d75effSDimitry Andric } 521*68d75effSDimitry Andric 522*68d75effSDimitry Andric uptr __asan_get_report_address() { 523*68d75effSDimitry Andric ErrorDescription &err = ScopedInErrorReport::CurrentError(); 524*68d75effSDimitry Andric if (err.kind == kErrorKindGeneric) 525*68d75effSDimitry Andric return err.Generic.addr_description.Address(); 526*68d75effSDimitry Andric else if (err.kind == kErrorKindDoubleFree) 527*68d75effSDimitry Andric return err.DoubleFree.addr_description.addr; 528*68d75effSDimitry Andric return 0; 529*68d75effSDimitry Andric } 530*68d75effSDimitry Andric 531*68d75effSDimitry Andric int __asan_get_report_access_type() { 532*68d75effSDimitry Andric if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric) 533*68d75effSDimitry Andric return ScopedInErrorReport::CurrentError().Generic.is_write; 534*68d75effSDimitry Andric return 0; 535*68d75effSDimitry Andric } 536*68d75effSDimitry Andric 537*68d75effSDimitry Andric uptr __asan_get_report_access_size() { 538*68d75effSDimitry Andric if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric) 539*68d75effSDimitry Andric return ScopedInErrorReport::CurrentError().Generic.access_size; 540*68d75effSDimitry Andric return 0; 541*68d75effSDimitry Andric } 542*68d75effSDimitry Andric 543*68d75effSDimitry Andric const char *__asan_get_report_description() { 544*68d75effSDimitry Andric if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric) 545*68d75effSDimitry Andric return ScopedInErrorReport::CurrentError().Generic.bug_descr; 546*68d75effSDimitry Andric return ScopedInErrorReport::CurrentError().Base.scariness.GetDescription(); 547*68d75effSDimitry Andric } 548*68d75effSDimitry Andric 549*68d75effSDimitry Andric extern "C" { 550*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 551*68d75effSDimitry Andric void __sanitizer_ptr_sub(void *a, void *b) { 552*68d75effSDimitry Andric CheckForInvalidPointerPair(a, b); 553*68d75effSDimitry Andric } 554*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 555*68d75effSDimitry Andric void __sanitizer_ptr_cmp(void *a, void *b) { 556*68d75effSDimitry Andric CheckForInvalidPointerPair(a, b); 557*68d75effSDimitry Andric } 558*68d75effSDimitry Andric } // extern "C" 559*68d75effSDimitry Andric 560*68d75effSDimitry Andric // Provide default implementation of __asan_on_error that does nothing 561*68d75effSDimitry Andric // and may be overriden by user. 562*68d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __asan_on_error, void) {} 563