1 //=-- lsan_common.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 LeakSanitizer. 10 // Implementation of common leak checking functionality. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "lsan_common.h" 15 16 #include "sanitizer_common/sanitizer_common.h" 17 #include "sanitizer_common/sanitizer_flag_parser.h" 18 #include "sanitizer_common/sanitizer_flags.h" 19 #include "sanitizer_common/sanitizer_placement_new.h" 20 #include "sanitizer_common/sanitizer_procmaps.h" 21 #include "sanitizer_common/sanitizer_report_decorator.h" 22 #include "sanitizer_common/sanitizer_stackdepot.h" 23 #include "sanitizer_common/sanitizer_stacktrace.h" 24 #include "sanitizer_common/sanitizer_suppressions.h" 25 #include "sanitizer_common/sanitizer_thread_registry.h" 26 #include "sanitizer_common/sanitizer_tls_get_addr.h" 27 28 #if CAN_SANITIZE_LEAKS 29 30 # if SANITIZER_APPLE 31 // https://github.com/apple-oss-distributions/objc4/blob/8701d5672d3fd3cd817aeb84db1077aafe1a1604/runtime/objc-runtime-new.h#L127 32 # if SANITIZER_IOS && !SANITIZER_IOSSIM 33 # define OBJC_DATA_MASK 0x0000007ffffffff8UL 34 # else 35 # define OBJC_DATA_MASK 0x00007ffffffffff8UL 36 # endif 37 // https://github.com/apple-oss-distributions/objc4/blob/8701d5672d3fd3cd817aeb84db1077aafe1a1604/runtime/objc-runtime-new.h#L139 38 # define OBJC_FAST_IS_RW 0x8000000000000000UL 39 # endif 40 41 namespace __lsan { 42 43 // This mutex is used to prevent races between DoLeakCheck and IgnoreObject, and 44 // also to protect the global list of root regions. 45 Mutex global_mutex; 46 47 Flags lsan_flags; 48 49 void DisableCounterUnderflow() { 50 if (common_flags()->detect_leaks) { 51 Report("Unmatched call to __lsan_enable().\n"); 52 Die(); 53 } 54 } 55 56 void Flags::SetDefaults() { 57 # define LSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; 58 # include "lsan_flags.inc" 59 # undef LSAN_FLAG 60 } 61 62 void RegisterLsanFlags(FlagParser *parser, Flags *f) { 63 # define LSAN_FLAG(Type, Name, DefaultValue, Description) \ 64 RegisterFlag(parser, #Name, Description, &f->Name); 65 # include "lsan_flags.inc" 66 # undef LSAN_FLAG 67 } 68 69 # define LOG_POINTERS(...) \ 70 do { \ 71 if (flags()->log_pointers) \ 72 Report(__VA_ARGS__); \ 73 } while (0) 74 75 # define LOG_THREADS(...) \ 76 do { \ 77 if (flags()->log_threads) \ 78 Report(__VA_ARGS__); \ 79 } while (0) 80 81 class LeakSuppressionContext { 82 bool parsed = false; 83 SuppressionContext context; 84 bool suppressed_stacks_sorted = true; 85 InternalMmapVector<u32> suppressed_stacks; 86 const LoadedModule *suppress_module = nullptr; 87 88 void LazyInit(); 89 Suppression *GetSuppressionForAddr(uptr addr); 90 bool SuppressInvalid(const StackTrace &stack); 91 bool SuppressByRule(const StackTrace &stack, uptr hit_count, uptr total_size); 92 93 public: 94 LeakSuppressionContext(const char *supprression_types[], 95 int suppression_types_num) 96 : context(supprression_types, suppression_types_num) {} 97 98 bool Suppress(u32 stack_trace_id, uptr hit_count, uptr total_size); 99 100 const InternalMmapVector<u32> &GetSortedSuppressedStacks() { 101 if (!suppressed_stacks_sorted) { 102 suppressed_stacks_sorted = true; 103 SortAndDedup(suppressed_stacks); 104 } 105 return suppressed_stacks; 106 } 107 void PrintMatchedSuppressions(); 108 }; 109 110 ALIGNED(64) static char suppression_placeholder[sizeof(LeakSuppressionContext)]; 111 static LeakSuppressionContext *suppression_ctx = nullptr; 112 static const char kSuppressionLeak[] = "leak"; 113 static const char *kSuppressionTypes[] = {kSuppressionLeak}; 114 static const char kStdSuppressions[] = 115 # if SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT 116 // For more details refer to the SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT 117 // definition. 118 "leak:*pthread_exit*\n" 119 # endif // SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT 120 # if SANITIZER_APPLE 121 // For Darwin and os_log/os_trace: https://reviews.llvm.org/D35173 122 "leak:*_os_trace*\n" 123 # endif 124 // TLS leak in some glibc versions, described in 125 // https://sourceware.org/bugzilla/show_bug.cgi?id=12650. 126 "leak:*tls_get_addr*\n"; 127 128 void InitializeSuppressions() { 129 CHECK_EQ(nullptr, suppression_ctx); 130 suppression_ctx = new (suppression_placeholder) 131 LeakSuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes)); 132 } 133 134 void LeakSuppressionContext::LazyInit() { 135 if (!parsed) { 136 parsed = true; 137 context.ParseFromFile(flags()->suppressions); 138 if (&__lsan_default_suppressions) 139 context.Parse(__lsan_default_suppressions()); 140 context.Parse(kStdSuppressions); 141 if (flags()->use_tls && flags()->use_ld_allocations) 142 suppress_module = GetLinker(); 143 } 144 } 145 146 Suppression *LeakSuppressionContext::GetSuppressionForAddr(uptr addr) { 147 Suppression *s = nullptr; 148 149 // Suppress by module name. 150 const char *module_name = Symbolizer::GetOrInit()->GetModuleNameForPc(addr); 151 if (!module_name) 152 module_name = "<unknown module>"; 153 if (context.Match(module_name, kSuppressionLeak, &s)) 154 return s; 155 156 // Suppress by file or function name. 157 SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(addr); 158 for (SymbolizedStack *cur = frames; cur; cur = cur->next) { 159 if (context.Match(cur->info.function, kSuppressionLeak, &s) || 160 context.Match(cur->info.file, kSuppressionLeak, &s)) { 161 break; 162 } 163 } 164 frames->ClearAll(); 165 return s; 166 } 167 168 static uptr GetCallerPC(const StackTrace &stack) { 169 // The top frame is our malloc/calloc/etc. The next frame is the caller. 170 if (stack.size >= 2) 171 return stack.trace[1]; 172 return 0; 173 } 174 175 # if SANITIZER_APPLE 176 // Objective-C class data pointers are stored with flags in the low bits, so 177 // they need to be transformed back into something that looks like a pointer. 178 static inline void *MaybeTransformPointer(void *p) { 179 uptr ptr = reinterpret_cast<uptr>(p); 180 if ((ptr & OBJC_FAST_IS_RW) == OBJC_FAST_IS_RW) 181 ptr &= OBJC_DATA_MASK; 182 return reinterpret_cast<void *>(ptr); 183 } 184 # endif 185 186 // On Linux, treats all chunks allocated from ld-linux.so as reachable, which 187 // covers dynamically allocated TLS blocks, internal dynamic loader's loaded 188 // modules accounting etc. 189 // Dynamic TLS blocks contain the TLS variables of dynamically loaded modules. 190 // They are allocated with a __libc_memalign() call in allocate_and_init() 191 // (elf/dl-tls.c). Glibc won't tell us the address ranges occupied by those 192 // blocks, but we can make sure they come from our own allocator by intercepting 193 // __libc_memalign(). On top of that, there is no easy way to reach them. Their 194 // addresses are stored in a dynamically allocated array (the DTV) which is 195 // referenced from the static TLS. Unfortunately, we can't just rely on the DTV 196 // being reachable from the static TLS, and the dynamic TLS being reachable from 197 // the DTV. This is because the initial DTV is allocated before our interception 198 // mechanism kicks in, and thus we don't recognize it as allocated memory. We 199 // can't special-case it either, since we don't know its size. 200 // Our solution is to include in the root set all allocations made from 201 // ld-linux.so (which is where allocate_and_init() is implemented). This is 202 // guaranteed to include all dynamic TLS blocks (and possibly other allocations 203 // which we don't care about). 204 // On all other platforms, this simply checks to ensure that the caller pc is 205 // valid before reporting chunks as leaked. 206 bool LeakSuppressionContext::SuppressInvalid(const StackTrace &stack) { 207 uptr caller_pc = GetCallerPC(stack); 208 // If caller_pc is unknown, this chunk may be allocated in a coroutine. Mark 209 // it as reachable, as we can't properly report its allocation stack anyway. 210 return !caller_pc || 211 (suppress_module && suppress_module->containsAddress(caller_pc)); 212 } 213 214 bool LeakSuppressionContext::SuppressByRule(const StackTrace &stack, 215 uptr hit_count, uptr total_size) { 216 for (uptr i = 0; i < stack.size; i++) { 217 Suppression *s = GetSuppressionForAddr( 218 StackTrace::GetPreviousInstructionPc(stack.trace[i])); 219 if (s) { 220 s->weight += total_size; 221 atomic_fetch_add(&s->hit_count, hit_count, memory_order_relaxed); 222 return true; 223 } 224 } 225 return false; 226 } 227 228 bool LeakSuppressionContext::Suppress(u32 stack_trace_id, uptr hit_count, 229 uptr total_size) { 230 LazyInit(); 231 StackTrace stack = StackDepotGet(stack_trace_id); 232 if (!SuppressInvalid(stack) && !SuppressByRule(stack, hit_count, total_size)) 233 return false; 234 suppressed_stacks_sorted = false; 235 suppressed_stacks.push_back(stack_trace_id); 236 return true; 237 } 238 239 static LeakSuppressionContext *GetSuppressionContext() { 240 CHECK(suppression_ctx); 241 return suppression_ctx; 242 } 243 244 static InternalMmapVectorNoCtor<RootRegion> root_regions; 245 246 InternalMmapVectorNoCtor<RootRegion> const *GetRootRegions() { 247 return &root_regions; 248 } 249 250 void InitCommonLsan() { 251 if (common_flags()->detect_leaks) { 252 // Initialization which can fail or print warnings should only be done if 253 // LSan is actually enabled. 254 InitializeSuppressions(); 255 InitializePlatformSpecificModules(); 256 } 257 } 258 259 class Decorator : public __sanitizer::SanitizerCommonDecorator { 260 public: 261 Decorator() : SanitizerCommonDecorator() {} 262 const char *Error() { return Red(); } 263 const char *Leak() { return Blue(); } 264 }; 265 266 static inline bool MaybeUserPointer(uptr p) { 267 // Since our heap is located in mmap-ed memory, we can assume a sensible lower 268 // bound on heap addresses. 269 const uptr kMinAddress = 4 * 4096; 270 if (p < kMinAddress) 271 return false; 272 # if defined(__x86_64__) 273 // Accept only canonical form user-space addresses. 274 return ((p >> 47) == 0); 275 # elif defined(__mips64) 276 return ((p >> 40) == 0); 277 # elif defined(__aarch64__) 278 // Accept up to 48 bit VMA. 279 return ((p >> 48) == 0); 280 # elif defined(__loongarch_lp64) 281 // Allow 47-bit user-space VMA at current. 282 return ((p >> 47) == 0); 283 # else 284 return true; 285 # endif 286 } 287 288 // Scans the memory range, looking for byte patterns that point into allocator 289 // chunks. Marks those chunks with |tag| and adds them to |frontier|. 290 // There are two usage modes for this function: finding reachable chunks 291 // (|tag| = kReachable) and finding indirectly leaked chunks 292 // (|tag| = kIndirectlyLeaked). In the second case, there's no flood fill, 293 // so |frontier| = 0. 294 void ScanRangeForPointers(uptr begin, uptr end, Frontier *frontier, 295 const char *region_type, ChunkTag tag) { 296 CHECK(tag == kReachable || tag == kIndirectlyLeaked); 297 const uptr alignment = flags()->pointer_alignment(); 298 LOG_POINTERS("Scanning %s range %p-%p.\n", region_type, (void *)begin, 299 (void *)end); 300 uptr pp = begin; 301 if (pp % alignment) 302 pp = pp + alignment - pp % alignment; 303 for (; pp + sizeof(void *) <= end; pp += alignment) { 304 void *p = *reinterpret_cast<void **>(pp); 305 # if SANITIZER_APPLE 306 p = MaybeTransformPointer(p); 307 # endif 308 if (!MaybeUserPointer(reinterpret_cast<uptr>(p))) 309 continue; 310 uptr chunk = PointsIntoChunk(p); 311 if (!chunk) 312 continue; 313 // Pointers to self don't count. This matters when tag == kIndirectlyLeaked. 314 if (chunk == begin) 315 continue; 316 LsanMetadata m(chunk); 317 if (m.tag() == kReachable || m.tag() == kIgnored) 318 continue; 319 320 // Do this check relatively late so we can log only the interesting cases. 321 if (!flags()->use_poisoned && WordIsPoisoned(pp)) { 322 LOG_POINTERS( 323 "%p is poisoned: ignoring %p pointing into chunk %p-%p of size " 324 "%zu.\n", 325 (void *)pp, p, (void *)chunk, (void *)(chunk + m.requested_size()), 326 m.requested_size()); 327 continue; 328 } 329 330 m.set_tag(tag); 331 LOG_POINTERS("%p: found %p pointing into chunk %p-%p of size %zu.\n", 332 (void *)pp, p, (void *)chunk, 333 (void *)(chunk + m.requested_size()), m.requested_size()); 334 if (frontier) 335 frontier->push_back(chunk); 336 } 337 } 338 339 // Scans a global range for pointers 340 void ScanGlobalRange(uptr begin, uptr end, Frontier *frontier) { 341 uptr allocator_begin = 0, allocator_end = 0; 342 GetAllocatorGlobalRange(&allocator_begin, &allocator_end); 343 if (begin <= allocator_begin && allocator_begin < end) { 344 CHECK_LE(allocator_begin, allocator_end); 345 CHECK_LE(allocator_end, end); 346 if (begin < allocator_begin) 347 ScanRangeForPointers(begin, allocator_begin, frontier, "GLOBAL", 348 kReachable); 349 if (allocator_end < end) 350 ScanRangeForPointers(allocator_end, end, frontier, "GLOBAL", kReachable); 351 } else { 352 ScanRangeForPointers(begin, end, frontier, "GLOBAL", kReachable); 353 } 354 } 355 356 void ScanExtraStackRanges(const InternalMmapVector<Range> &ranges, 357 Frontier *frontier) { 358 for (uptr i = 0; i < ranges.size(); i++) { 359 ScanRangeForPointers(ranges[i].begin, ranges[i].end, frontier, "FAKE STACK", 360 kReachable); 361 } 362 } 363 364 # if SANITIZER_FUCHSIA 365 366 // Fuchsia handles all threads together with its own callback. 367 static void ProcessThreads(SuspendedThreadsList const &, Frontier *, tid_t, 368 uptr) {} 369 370 # else 371 372 # if SANITIZER_ANDROID 373 // FIXME: Move this out into *libcdep.cpp 374 extern "C" SANITIZER_WEAK_ATTRIBUTE void __libc_iterate_dynamic_tls( 375 pid_t, void (*cb)(void *, void *, uptr, void *), void *); 376 # endif 377 378 static void ProcessThreadRegistry(Frontier *frontier) { 379 InternalMmapVector<uptr> ptrs; 380 GetAdditionalThreadContextPtrsLocked(&ptrs); 381 382 for (uptr i = 0; i < ptrs.size(); ++i) { 383 void *ptr = reinterpret_cast<void *>(ptrs[i]); 384 uptr chunk = PointsIntoChunk(ptr); 385 if (!chunk) 386 continue; 387 LsanMetadata m(chunk); 388 if (!m.allocated()) 389 continue; 390 391 // Mark as reachable and add to frontier. 392 LOG_POINTERS("Treating pointer %p from ThreadContext as reachable\n", ptr); 393 m.set_tag(kReachable); 394 frontier->push_back(chunk); 395 } 396 } 397 398 // Scans thread data (stacks and TLS) for heap pointers. 399 static void ProcessThreads(SuspendedThreadsList const &suspended_threads, 400 Frontier *frontier, tid_t caller_tid, 401 uptr caller_sp) { 402 InternalMmapVector<uptr> registers; 403 InternalMmapVector<Range> extra_ranges; 404 for (uptr i = 0; i < suspended_threads.ThreadCount(); i++) { 405 tid_t os_id = static_cast<tid_t>(suspended_threads.GetThreadID(i)); 406 LOG_THREADS("Processing thread %llu.\n", os_id); 407 uptr stack_begin, stack_end, tls_begin, tls_end, cache_begin, cache_end; 408 DTLS *dtls; 409 bool thread_found = 410 GetThreadRangesLocked(os_id, &stack_begin, &stack_end, &tls_begin, 411 &tls_end, &cache_begin, &cache_end, &dtls); 412 if (!thread_found) { 413 // If a thread can't be found in the thread registry, it's probably in the 414 // process of destruction. Log this event and move on. 415 LOG_THREADS("Thread %llu not found in registry.\n", os_id); 416 continue; 417 } 418 uptr sp; 419 PtraceRegistersStatus have_registers = 420 suspended_threads.GetRegistersAndSP(i, ®isters, &sp); 421 if (have_registers != REGISTERS_AVAILABLE) { 422 Report("Unable to get registers from thread %llu.\n", os_id); 423 // If unable to get SP, consider the entire stack to be reachable unless 424 // GetRegistersAndSP failed with ESRCH. 425 if (have_registers == REGISTERS_UNAVAILABLE_FATAL) 426 continue; 427 sp = stack_begin; 428 } 429 if (suspended_threads.GetThreadID(i) == caller_tid) { 430 sp = caller_sp; 431 } 432 433 if (flags()->use_registers && have_registers) { 434 uptr registers_begin = reinterpret_cast<uptr>(registers.data()); 435 uptr registers_end = 436 reinterpret_cast<uptr>(registers.data() + registers.size()); 437 ScanRangeForPointers(registers_begin, registers_end, frontier, 438 "REGISTERS", kReachable); 439 } 440 441 if (flags()->use_stacks) { 442 LOG_THREADS("Stack at %p-%p (SP = %p).\n", (void *)stack_begin, 443 (void *)stack_end, (void *)sp); 444 if (sp < stack_begin || sp >= stack_end) { 445 // SP is outside the recorded stack range (e.g. the thread is running a 446 // signal handler on alternate stack, or swapcontext was used). 447 // Again, consider the entire stack range to be reachable. 448 LOG_THREADS("WARNING: stack pointer not in stack range.\n"); 449 uptr page_size = GetPageSizeCached(); 450 int skipped = 0; 451 while (stack_begin < stack_end && 452 !IsAccessibleMemoryRange(stack_begin, 1)) { 453 skipped++; 454 stack_begin += page_size; 455 } 456 LOG_THREADS("Skipped %d guard page(s) to obtain stack %p-%p.\n", 457 skipped, (void *)stack_begin, (void *)stack_end); 458 } else { 459 // Shrink the stack range to ignore out-of-scope values. 460 stack_begin = sp; 461 } 462 ScanRangeForPointers(stack_begin, stack_end, frontier, "STACK", 463 kReachable); 464 extra_ranges.clear(); 465 GetThreadExtraStackRangesLocked(os_id, &extra_ranges); 466 ScanExtraStackRanges(extra_ranges, frontier); 467 } 468 469 if (flags()->use_tls) { 470 if (tls_begin) { 471 LOG_THREADS("TLS at %p-%p.\n", (void *)tls_begin, (void *)tls_end); 472 // If the tls and cache ranges don't overlap, scan full tls range, 473 // otherwise, only scan the non-overlapping portions 474 if (cache_begin == cache_end || tls_end < cache_begin || 475 tls_begin > cache_end) { 476 ScanRangeForPointers(tls_begin, tls_end, frontier, "TLS", kReachable); 477 } else { 478 if (tls_begin < cache_begin) 479 ScanRangeForPointers(tls_begin, cache_begin, frontier, "TLS", 480 kReachable); 481 if (tls_end > cache_end) 482 ScanRangeForPointers(cache_end, tls_end, frontier, "TLS", 483 kReachable); 484 } 485 } 486 # if SANITIZER_ANDROID 487 auto *cb = +[](void *dtls_begin, void *dtls_end, uptr /*dso_idd*/, 488 void *arg) -> void { 489 ScanRangeForPointers(reinterpret_cast<uptr>(dtls_begin), 490 reinterpret_cast<uptr>(dtls_end), 491 reinterpret_cast<Frontier *>(arg), "DTLS", 492 kReachable); 493 }; 494 495 // FIXME: There might be a race-condition here (and in Bionic) if the 496 // thread is suspended in the middle of updating its DTLS. IOWs, we 497 // could scan already freed memory. (probably fine for now) 498 __libc_iterate_dynamic_tls(os_id, cb, frontier); 499 # else 500 if (dtls && !DTLSInDestruction(dtls)) { 501 ForEachDVT(dtls, [&](const DTLS::DTV &dtv, int id) { 502 uptr dtls_beg = dtv.beg; 503 uptr dtls_end = dtls_beg + dtv.size; 504 if (dtls_beg < dtls_end) { 505 LOG_THREADS("DTLS %d at %p-%p.\n", id, (void *)dtls_beg, 506 (void *)dtls_end); 507 ScanRangeForPointers(dtls_beg, dtls_end, frontier, "DTLS", 508 kReachable); 509 } 510 }); 511 } else { 512 // We are handling a thread with DTLS under destruction. Log about 513 // this and continue. 514 LOG_THREADS("Thread %llu has DTLS under destruction.\n", os_id); 515 } 516 # endif 517 } 518 } 519 520 // Add pointers reachable from ThreadContexts 521 ProcessThreadRegistry(frontier); 522 } 523 524 # endif // SANITIZER_FUCHSIA 525 526 void ScanRootRegion(Frontier *frontier, const RootRegion &root_region, 527 uptr region_begin, uptr region_end, bool is_readable) { 528 uptr intersection_begin = Max(root_region.begin, region_begin); 529 uptr intersection_end = Min(region_end, root_region.begin + root_region.size); 530 if (intersection_begin >= intersection_end) 531 return; 532 LOG_POINTERS("Root region %p-%p intersects with mapped region %p-%p (%s)\n", 533 (void *)root_region.begin, 534 (void *)(root_region.begin + root_region.size), 535 (void *)region_begin, (void *)region_end, 536 is_readable ? "readable" : "unreadable"); 537 if (is_readable) 538 ScanRangeForPointers(intersection_begin, intersection_end, frontier, "ROOT", 539 kReachable); 540 } 541 542 static void ProcessRootRegion(Frontier *frontier, 543 const RootRegion &root_region) { 544 MemoryMappingLayout proc_maps(/*cache_enabled*/ true); 545 MemoryMappedSegment segment; 546 while (proc_maps.Next(&segment)) { 547 ScanRootRegion(frontier, root_region, segment.start, segment.end, 548 segment.IsReadable()); 549 } 550 } 551 552 // Scans root regions for heap pointers. 553 static void ProcessRootRegions(Frontier *frontier) { 554 if (!flags()->use_root_regions) 555 return; 556 for (uptr i = 0; i < root_regions.size(); i++) 557 ProcessRootRegion(frontier, root_regions[i]); 558 } 559 560 static void FloodFillTag(Frontier *frontier, ChunkTag tag) { 561 while (frontier->size()) { 562 uptr next_chunk = frontier->back(); 563 frontier->pop_back(); 564 LsanMetadata m(next_chunk); 565 ScanRangeForPointers(next_chunk, next_chunk + m.requested_size(), frontier, 566 "HEAP", tag); 567 } 568 } 569 570 // ForEachChunk callback. If the chunk is marked as leaked, marks all chunks 571 // which are reachable from it as indirectly leaked. 572 static void MarkIndirectlyLeakedCb(uptr chunk, void *arg) { 573 chunk = GetUserBegin(chunk); 574 LsanMetadata m(chunk); 575 if (m.allocated() && m.tag() != kReachable) { 576 ScanRangeForPointers(chunk, chunk + m.requested_size(), 577 /* frontier */ nullptr, "HEAP", kIndirectlyLeaked); 578 } 579 } 580 581 static void IgnoredSuppressedCb(uptr chunk, void *arg) { 582 CHECK(arg); 583 chunk = GetUserBegin(chunk); 584 LsanMetadata m(chunk); 585 if (!m.allocated() || m.tag() == kIgnored) 586 return; 587 588 const InternalMmapVector<u32> &suppressed = 589 *static_cast<const InternalMmapVector<u32> *>(arg); 590 uptr idx = InternalLowerBound(suppressed, m.stack_trace_id()); 591 if (idx >= suppressed.size() || m.stack_trace_id() != suppressed[idx]) 592 return; 593 594 LOG_POINTERS("Suppressed: chunk %p-%p of size %zu.\n", (void *)chunk, 595 (void *)(chunk + m.requested_size()), m.requested_size()); 596 m.set_tag(kIgnored); 597 } 598 599 // ForEachChunk callback. If chunk is marked as ignored, adds its address to 600 // frontier. 601 static void CollectIgnoredCb(uptr chunk, void *arg) { 602 CHECK(arg); 603 chunk = GetUserBegin(chunk); 604 LsanMetadata m(chunk); 605 if (m.allocated() && m.tag() == kIgnored) { 606 LOG_POINTERS("Ignored: chunk %p-%p of size %zu.\n", (void *)chunk, 607 (void *)(chunk + m.requested_size()), m.requested_size()); 608 reinterpret_cast<Frontier *>(arg)->push_back(chunk); 609 } 610 } 611 612 // Sets the appropriate tag on each chunk. 613 static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads, 614 Frontier *frontier, tid_t caller_tid, 615 uptr caller_sp) { 616 const InternalMmapVector<u32> &suppressed_stacks = 617 GetSuppressionContext()->GetSortedSuppressedStacks(); 618 if (!suppressed_stacks.empty()) { 619 ForEachChunk(IgnoredSuppressedCb, 620 const_cast<InternalMmapVector<u32> *>(&suppressed_stacks)); 621 } 622 ForEachChunk(CollectIgnoredCb, frontier); 623 ProcessGlobalRegions(frontier); 624 ProcessThreads(suspended_threads, frontier, caller_tid, caller_sp); 625 ProcessRootRegions(frontier); 626 FloodFillTag(frontier, kReachable); 627 628 // The check here is relatively expensive, so we do this in a separate flood 629 // fill. That way we can skip the check for chunks that are reachable 630 // otherwise. 631 LOG_POINTERS("Processing platform-specific allocations.\n"); 632 ProcessPlatformSpecificAllocations(frontier); 633 FloodFillTag(frontier, kReachable); 634 635 // Iterate over leaked chunks and mark those that are reachable from other 636 // leaked chunks. 637 LOG_POINTERS("Scanning leaked chunks.\n"); 638 ForEachChunk(MarkIndirectlyLeakedCb, nullptr); 639 } 640 641 // ForEachChunk callback. Resets the tags to pre-leak-check state. 642 static void ResetTagsCb(uptr chunk, void *arg) { 643 (void)arg; 644 chunk = GetUserBegin(chunk); 645 LsanMetadata m(chunk); 646 if (m.allocated() && m.tag() != kIgnored) 647 m.set_tag(kDirectlyLeaked); 648 } 649 650 // ForEachChunk callback. Aggregates information about unreachable chunks into 651 // a LeakReport. 652 static void CollectLeaksCb(uptr chunk, void *arg) { 653 CHECK(arg); 654 LeakedChunks *leaks = reinterpret_cast<LeakedChunks *>(arg); 655 chunk = GetUserBegin(chunk); 656 LsanMetadata m(chunk); 657 if (!m.allocated()) 658 return; 659 if (m.tag() == kDirectlyLeaked || m.tag() == kIndirectlyLeaked) 660 leaks->push_back({chunk, m.stack_trace_id(), m.requested_size(), m.tag()}); 661 } 662 663 void LeakSuppressionContext::PrintMatchedSuppressions() { 664 InternalMmapVector<Suppression *> matched; 665 context.GetMatched(&matched); 666 if (!matched.size()) 667 return; 668 const char *line = "-----------------------------------------------------"; 669 Printf("%s\n", line); 670 Printf("Suppressions used:\n"); 671 Printf(" count bytes template\n"); 672 for (uptr i = 0; i < matched.size(); i++) { 673 Printf("%7zu %10zu %s\n", 674 static_cast<uptr>(atomic_load_relaxed(&matched[i]->hit_count)), 675 matched[i]->weight, matched[i]->templ); 676 } 677 Printf("%s\n\n", line); 678 } 679 680 # if SANITIZER_FUCHSIA 681 682 // Fuchsia provides a libc interface that guarantees all threads are 683 // covered, and SuspendedThreadList is never really used. 684 static void ReportUnsuspendedThreads(const SuspendedThreadsList &) {} 685 686 # else // !SANITIZER_FUCHSIA 687 688 static void ReportUnsuspendedThreads( 689 const SuspendedThreadsList &suspended_threads) { 690 InternalMmapVector<tid_t> threads(suspended_threads.ThreadCount()); 691 for (uptr i = 0; i < suspended_threads.ThreadCount(); ++i) 692 threads[i] = suspended_threads.GetThreadID(i); 693 694 Sort(threads.data(), threads.size()); 695 696 InternalMmapVector<tid_t> unsuspended; 697 GetRunningThreadsLocked(&unsuspended); 698 699 for (auto os_id : unsuspended) { 700 uptr i = InternalLowerBound(threads, os_id); 701 if (i >= threads.size() || threads[i] != os_id) 702 Report( 703 "Running thread %zu was not suspended. False leaks are possible.\n", 704 os_id); 705 } 706 } 707 708 # endif // !SANITIZER_FUCHSIA 709 710 static void CheckForLeaksCallback(const SuspendedThreadsList &suspended_threads, 711 void *arg) { 712 CheckForLeaksParam *param = reinterpret_cast<CheckForLeaksParam *>(arg); 713 CHECK(param); 714 CHECK(!param->success); 715 ReportUnsuspendedThreads(suspended_threads); 716 ClassifyAllChunks(suspended_threads, ¶m->frontier, param->caller_tid, 717 param->caller_sp); 718 ForEachChunk(CollectLeaksCb, ¶m->leaks); 719 // Clean up for subsequent leak checks. This assumes we did not overwrite any 720 // kIgnored tags. 721 ForEachChunk(ResetTagsCb, nullptr); 722 param->success = true; 723 } 724 725 static bool PrintResults(LeakReport &report) { 726 uptr unsuppressed_count = report.UnsuppressedLeakCount(); 727 if (unsuppressed_count) { 728 Decorator d; 729 Printf( 730 "\n" 731 "=================================================================" 732 "\n"); 733 Printf("%s", d.Error()); 734 Report("ERROR: LeakSanitizer: detected memory leaks\n"); 735 Printf("%s", d.Default()); 736 report.ReportTopLeaks(flags()->max_leaks); 737 } 738 if (common_flags()->print_suppressions) 739 GetSuppressionContext()->PrintMatchedSuppressions(); 740 if (unsuppressed_count > 0) { 741 report.PrintSummary(); 742 return true; 743 } 744 return false; 745 } 746 747 static bool CheckForLeaks() { 748 if (&__lsan_is_turned_off && __lsan_is_turned_off()) { 749 VReport(1, "LeakSanitizer is disabled"); 750 return false; 751 } 752 VReport(1, "LeakSanitizer: checking for leaks"); 753 // Inside LockStuffAndStopTheWorld we can't run symbolizer, so we can't match 754 // suppressions. However if a stack id was previously suppressed, it should be 755 // suppressed in future checks as well. 756 for (int i = 0;; ++i) { 757 EnsureMainThreadIDIsCorrect(); 758 CheckForLeaksParam param; 759 // Capture calling thread's stack pointer early, to avoid false negatives. 760 // Old frame with dead pointers might be overlapped by new frame inside 761 // CheckForLeaks which does not use bytes with pointers before the 762 // threads are suspended and stack pointers captured. 763 param.caller_tid = GetTid(); 764 param.caller_sp = reinterpret_cast<uptr>(__builtin_frame_address(0)); 765 LockStuffAndStopTheWorld(CheckForLeaksCallback, ¶m); 766 if (!param.success) { 767 Report("LeakSanitizer has encountered a fatal error.\n"); 768 Report( 769 "HINT: For debugging, try setting environment variable " 770 "LSAN_OPTIONS=verbosity=1:log_threads=1\n"); 771 Report( 772 "HINT: LeakSanitizer does not work under ptrace (strace, gdb, " 773 "etc)\n"); 774 Die(); 775 } 776 LeakReport leak_report; 777 leak_report.AddLeakedChunks(param.leaks); 778 779 // No new suppressions stacks, so rerun will not help and we can report. 780 if (!leak_report.ApplySuppressions()) 781 return PrintResults(leak_report); 782 783 // No indirect leaks to report, so we are done here. 784 if (!leak_report.IndirectUnsuppressedLeakCount()) 785 return PrintResults(leak_report); 786 787 if (i >= 8) { 788 Report("WARNING: LeakSanitizer gave up on indirect leaks suppression.\n"); 789 return PrintResults(leak_report); 790 } 791 792 // We found a new previously unseen suppressed call stack. Rerun to make 793 // sure it does not hold indirect leaks. 794 VReport(1, "Rerun with %zu suppressed stacks.", 795 GetSuppressionContext()->GetSortedSuppressedStacks().size()); 796 } 797 } 798 799 static bool has_reported_leaks = false; 800 bool HasReportedLeaks() { return has_reported_leaks; } 801 802 void DoLeakCheck() { 803 Lock l(&global_mutex); 804 static bool already_done; 805 if (already_done) 806 return; 807 already_done = true; 808 has_reported_leaks = CheckForLeaks(); 809 if (has_reported_leaks) 810 HandleLeaks(); 811 } 812 813 static int DoRecoverableLeakCheck() { 814 Lock l(&global_mutex); 815 bool have_leaks = CheckForLeaks(); 816 return have_leaks ? 1 : 0; 817 } 818 819 void DoRecoverableLeakCheckVoid() { DoRecoverableLeakCheck(); } 820 821 ///// LeakReport implementation. ///// 822 823 // A hard limit on the number of distinct leaks, to avoid quadratic complexity 824 // in LeakReport::AddLeakedChunk(). We don't expect to ever see this many leaks 825 // in real-world applications. 826 // FIXME: Get rid of this limit by moving logic into DedupLeaks. 827 const uptr kMaxLeaksConsidered = 5000; 828 829 void LeakReport::AddLeakedChunks(const LeakedChunks &chunks) { 830 for (const LeakedChunk &leak : chunks) { 831 uptr chunk = leak.chunk; 832 u32 stack_trace_id = leak.stack_trace_id; 833 uptr leaked_size = leak.leaked_size; 834 ChunkTag tag = leak.tag; 835 CHECK(tag == kDirectlyLeaked || tag == kIndirectlyLeaked); 836 837 if (u32 resolution = flags()->resolution) { 838 StackTrace stack = StackDepotGet(stack_trace_id); 839 stack.size = Min(stack.size, resolution); 840 stack_trace_id = StackDepotPut(stack); 841 } 842 843 bool is_directly_leaked = (tag == kDirectlyLeaked); 844 uptr i; 845 for (i = 0; i < leaks_.size(); i++) { 846 if (leaks_[i].stack_trace_id == stack_trace_id && 847 leaks_[i].is_directly_leaked == is_directly_leaked) { 848 leaks_[i].hit_count++; 849 leaks_[i].total_size += leaked_size; 850 break; 851 } 852 } 853 if (i == leaks_.size()) { 854 if (leaks_.size() == kMaxLeaksConsidered) 855 return; 856 Leak leak = {next_id_++, /* hit_count */ 1, 857 leaked_size, stack_trace_id, 858 is_directly_leaked, /* is_suppressed */ false}; 859 leaks_.push_back(leak); 860 } 861 if (flags()->report_objects) { 862 LeakedObject obj = {leaks_[i].id, chunk, leaked_size}; 863 leaked_objects_.push_back(obj); 864 } 865 } 866 } 867 868 static bool LeakComparator(const Leak &leak1, const Leak &leak2) { 869 if (leak1.is_directly_leaked == leak2.is_directly_leaked) 870 return leak1.total_size > leak2.total_size; 871 else 872 return leak1.is_directly_leaked; 873 } 874 875 void LeakReport::ReportTopLeaks(uptr num_leaks_to_report) { 876 CHECK(leaks_.size() <= kMaxLeaksConsidered); 877 Printf("\n"); 878 if (leaks_.size() == kMaxLeaksConsidered) 879 Printf( 880 "Too many leaks! Only the first %zu leaks encountered will be " 881 "reported.\n", 882 kMaxLeaksConsidered); 883 884 uptr unsuppressed_count = UnsuppressedLeakCount(); 885 if (num_leaks_to_report > 0 && num_leaks_to_report < unsuppressed_count) 886 Printf("The %zu top leak(s):\n", num_leaks_to_report); 887 Sort(leaks_.data(), leaks_.size(), &LeakComparator); 888 uptr leaks_reported = 0; 889 for (uptr i = 0; i < leaks_.size(); i++) { 890 if (leaks_[i].is_suppressed) 891 continue; 892 PrintReportForLeak(i); 893 leaks_reported++; 894 if (leaks_reported == num_leaks_to_report) 895 break; 896 } 897 if (leaks_reported < unsuppressed_count) { 898 uptr remaining = unsuppressed_count - leaks_reported; 899 Printf("Omitting %zu more leak(s).\n", remaining); 900 } 901 } 902 903 void LeakReport::PrintReportForLeak(uptr index) { 904 Decorator d; 905 Printf("%s", d.Leak()); 906 Printf("%s leak of %zu byte(s) in %zu object(s) allocated from:\n", 907 leaks_[index].is_directly_leaked ? "Direct" : "Indirect", 908 leaks_[index].total_size, leaks_[index].hit_count); 909 Printf("%s", d.Default()); 910 911 CHECK(leaks_[index].stack_trace_id); 912 StackDepotGet(leaks_[index].stack_trace_id).Print(); 913 914 if (flags()->report_objects) { 915 Printf("Objects leaked above:\n"); 916 PrintLeakedObjectsForLeak(index); 917 Printf("\n"); 918 } 919 } 920 921 void LeakReport::PrintLeakedObjectsForLeak(uptr index) { 922 u32 leak_id = leaks_[index].id; 923 for (uptr j = 0; j < leaked_objects_.size(); j++) { 924 if (leaked_objects_[j].leak_id == leak_id) 925 Printf("%p (%zu bytes)\n", (void *)leaked_objects_[j].addr, 926 leaked_objects_[j].size); 927 } 928 } 929 930 void LeakReport::PrintSummary() { 931 CHECK(leaks_.size() <= kMaxLeaksConsidered); 932 uptr bytes = 0, allocations = 0; 933 for (uptr i = 0; i < leaks_.size(); i++) { 934 if (leaks_[i].is_suppressed) 935 continue; 936 bytes += leaks_[i].total_size; 937 allocations += leaks_[i].hit_count; 938 } 939 InternalScopedString summary; 940 summary.append("%zu byte(s) leaked in %zu allocation(s).", bytes, 941 allocations); 942 ReportErrorSummary(summary.data()); 943 } 944 945 uptr LeakReport::ApplySuppressions() { 946 LeakSuppressionContext *suppressions = GetSuppressionContext(); 947 uptr new_suppressions = false; 948 for (uptr i = 0; i < leaks_.size(); i++) { 949 if (suppressions->Suppress(leaks_[i].stack_trace_id, leaks_[i].hit_count, 950 leaks_[i].total_size)) { 951 leaks_[i].is_suppressed = true; 952 ++new_suppressions; 953 } 954 } 955 return new_suppressions; 956 } 957 958 uptr LeakReport::UnsuppressedLeakCount() { 959 uptr result = 0; 960 for (uptr i = 0; i < leaks_.size(); i++) 961 if (!leaks_[i].is_suppressed) 962 result++; 963 return result; 964 } 965 966 uptr LeakReport::IndirectUnsuppressedLeakCount() { 967 uptr result = 0; 968 for (uptr i = 0; i < leaks_.size(); i++) 969 if (!leaks_[i].is_suppressed && !leaks_[i].is_directly_leaked) 970 result++; 971 return result; 972 } 973 974 } // namespace __lsan 975 #else // CAN_SANITIZE_LEAKS 976 namespace __lsan { 977 void InitCommonLsan() {} 978 void DoLeakCheck() {} 979 void DoRecoverableLeakCheckVoid() {} 980 void DisableInThisThread() {} 981 void EnableInThisThread() {} 982 } // namespace __lsan 983 #endif // CAN_SANITIZE_LEAKS 984 985 using namespace __lsan; 986 987 extern "C" { 988 SANITIZER_INTERFACE_ATTRIBUTE 989 void __lsan_ignore_object(const void *p) { 990 #if CAN_SANITIZE_LEAKS 991 if (!common_flags()->detect_leaks) 992 return; 993 // Cannot use PointsIntoChunk or LsanMetadata here, since the allocator is not 994 // locked. 995 Lock l(&global_mutex); 996 IgnoreObjectResult res = IgnoreObjectLocked(p); 997 if (res == kIgnoreObjectInvalid) 998 VReport(1, "__lsan_ignore_object(): no heap object found at %p\n", p); 999 if (res == kIgnoreObjectAlreadyIgnored) 1000 VReport(1, 1001 "__lsan_ignore_object(): " 1002 "heap object at %p is already being ignored\n", 1003 p); 1004 if (res == kIgnoreObjectSuccess) 1005 VReport(1, "__lsan_ignore_object(): ignoring heap object at %p\n", p); 1006 #endif // CAN_SANITIZE_LEAKS 1007 } 1008 1009 SANITIZER_INTERFACE_ATTRIBUTE 1010 void __lsan_register_root_region(const void *begin, uptr size) { 1011 #if CAN_SANITIZE_LEAKS 1012 Lock l(&global_mutex); 1013 RootRegion region = {reinterpret_cast<uptr>(begin), size}; 1014 root_regions.push_back(region); 1015 VReport(1, "Registered root region at %p of size %zu\n", begin, size); 1016 #endif // CAN_SANITIZE_LEAKS 1017 } 1018 1019 SANITIZER_INTERFACE_ATTRIBUTE 1020 void __lsan_unregister_root_region(const void *begin, uptr size) { 1021 #if CAN_SANITIZE_LEAKS 1022 Lock l(&global_mutex); 1023 bool removed = false; 1024 for (uptr i = 0; i < root_regions.size(); i++) { 1025 RootRegion region = root_regions[i]; 1026 if (region.begin == reinterpret_cast<uptr>(begin) && region.size == size) { 1027 removed = true; 1028 uptr last_index = root_regions.size() - 1; 1029 root_regions[i] = root_regions[last_index]; 1030 root_regions.pop_back(); 1031 VReport(1, "Unregistered root region at %p of size %zu\n", begin, size); 1032 break; 1033 } 1034 } 1035 if (!removed) { 1036 Report( 1037 "__lsan_unregister_root_region(): region at %p of size %zu has not " 1038 "been registered.\n", 1039 begin, size); 1040 Die(); 1041 } 1042 #endif // CAN_SANITIZE_LEAKS 1043 } 1044 1045 SANITIZER_INTERFACE_ATTRIBUTE 1046 void __lsan_disable() { 1047 #if CAN_SANITIZE_LEAKS 1048 __lsan::DisableInThisThread(); 1049 #endif 1050 } 1051 1052 SANITIZER_INTERFACE_ATTRIBUTE 1053 void __lsan_enable() { 1054 #if CAN_SANITIZE_LEAKS 1055 __lsan::EnableInThisThread(); 1056 #endif 1057 } 1058 1059 SANITIZER_INTERFACE_ATTRIBUTE 1060 void __lsan_do_leak_check() { 1061 #if CAN_SANITIZE_LEAKS 1062 if (common_flags()->detect_leaks) 1063 __lsan::DoLeakCheck(); 1064 #endif // CAN_SANITIZE_LEAKS 1065 } 1066 1067 SANITIZER_INTERFACE_ATTRIBUTE 1068 int __lsan_do_recoverable_leak_check() { 1069 #if CAN_SANITIZE_LEAKS 1070 if (common_flags()->detect_leaks) 1071 return __lsan::DoRecoverableLeakCheck(); 1072 #endif // CAN_SANITIZE_LEAKS 1073 return 0; 1074 } 1075 1076 SANITIZER_INTERFACE_WEAK_DEF(const char *, __lsan_default_options, void) { 1077 return ""; 1078 } 1079 1080 #if !SANITIZER_SUPPORTS_WEAK_HOOKS 1081 SANITIZER_INTERFACE_WEAK_DEF(int, __lsan_is_turned_off, void) { 1082 return 0; 1083 } 1084 1085 SANITIZER_INTERFACE_WEAK_DEF(const char *, __lsan_default_suppressions, void) { 1086 return ""; 1087 } 1088 #endif 1089 } // extern "C" 1090