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