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