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