lsan_common.cc revision 6c3634b1d5eeb0bffea01df10caa7168c48c8c5d
18d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S//=-- lsan_common.cc ------------------------------------------------------===// 28d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// 38d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// The LLVM Compiler Infrastructure 48d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// 58d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// This file is distributed under the University of Illinois Open Source 68d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// License. See LICENSE.TXT for details. 78d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// 88d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S//===----------------------------------------------------------------------===// 98d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// 108d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// This file is a part of LeakSanitizer. 118d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// Implementation of common leak checking functionality. 128d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// 138d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S//===----------------------------------------------------------------------===// 148d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 158d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S#include "lsan_common.h" 168d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 178d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S#include "sanitizer_common/sanitizer_common.h" 188d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S#include "sanitizer_common/sanitizer_flags.h" 198d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S#include "sanitizer_common/sanitizer_stackdepot.h" 208d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S#include "sanitizer_common/sanitizer_stacktrace.h" 218d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S#include "sanitizer_common/sanitizer_stoptheworld.h" 228d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 238d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S#if CAN_SANITIZE_LEAKS 248d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Snamespace __lsan { 258d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 268d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha SFlags lsan_flags; 278d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 288d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Sstatic void InitializeFlags() { 298d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S Flags *f = flags(); 308d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S // Default values. 318d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S f->sources = kSourceAllAligned; 328d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S f->report_blocks = false; 338d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S f->resolution = 0; 348d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S f->max_leaks = 0; 358d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S f->exitcode = 23; 368d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S f->log_pointers = false; 378d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S f->log_threads = false; 388d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 398d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S const char *options = GetEnv("LSAN_OPTIONS"); 408d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (options) { 418d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S bool aligned = true; 428d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S ParseFlag(options, &aligned, "aligned"); 438d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (!aligned) f->sources |= kSourceUnaligned; 448d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S ParseFlag(options, &f->report_blocks, "report_blocks"); 458d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S ParseFlag(options, &f->resolution, "resolution"); 468d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S CHECK_GE(&f->resolution, 0); 478d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S ParseFlag(options, &f->max_leaks, "max_leaks"); 488d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S CHECK_GE(&f->max_leaks, 0); 498d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S ParseFlag(options, &f->log_pointers, "log_pointers"); 508d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S ParseFlag(options, &f->log_threads, "log_threads"); 518d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S ParseFlag(options, &f->exitcode, "exitcode"); 528d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S } 538d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S} 548d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 558d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Svoid InitCommonLsan() { 568d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S InitializeFlags(); 578d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S InitializePlatformSpecificModules(); 588d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S} 598d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 608d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Sstatic inline bool CanBeAHeapPointer(uptr p) { 618d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S // Since our heap is located in mmap-ed memory, we can assume a sensible lower 628d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S // boundary on heap addresses. 638d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S const uptr kMinAddress = 4 * 4096; 648d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (p < kMinAddress) return false; 65134291ea0b1b9794b4d7feee2c3ffdbd941c5237Harinarayanan K K#ifdef __x86_64__ 668d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S // Accept only canonical form user-space addresses. 678d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S return ((p >> 47) == 0); 688d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S#else 698d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S return true; 708d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S#endif 718d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S} 728d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 738d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// Scan the memory range, looking for byte patterns that point into allocator 748d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// chunks. Mark those chunks with tag and add them to the frontier. 758d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// There are two usage modes for this function: finding non-leaked chunks 768d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// (tag = kReachable) and finding indirectly leaked chunks 778d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// (tag = kIndirectlyLeaked). In the second case, there's no flood fill, 788d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// so frontier = 0. 798d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Svoid ScanRangeForPointers(uptr begin, uptr end, InternalVector<uptr> *frontier, 808d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S const char *region_type, ChunkTag tag) { 818d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S const uptr alignment = flags()->pointer_alignment(); 828d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (flags()->log_pointers) 83134291ea0b1b9794b4d7feee2c3ffdbd941c5237Harinarayanan K K Report("Scanning %s range %p-%p.\n", region_type, begin, end); 848d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S uptr pp = begin; 858d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (pp % alignment) 868d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S pp = pp + alignment - pp % alignment; 878d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S for (; pp + sizeof(uptr) <= end; pp += alignment) { 888d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S void *p = *reinterpret_cast<void**>(pp); 898d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (!CanBeAHeapPointer(reinterpret_cast<uptr>(p))) continue; 90134291ea0b1b9794b4d7feee2c3ffdbd941c5237Harinarayanan K K // FIXME: PointsIntoChunk is SLOW because GetBlockBegin() in 918d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S // LargeMmapAllocator involves a lock and a linear search. 928d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S void *chunk = PointsIntoChunk(p); 938d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (!chunk) continue; 948d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S LsanMetadata m(chunk); 958d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (m.tag() == kReachable) continue; 968d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S m.set_tag(tag); 978d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (flags()->log_pointers) 988d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S Report("%p: found %p pointing into chunk %p-%p of size %llu.\n", pp, p, 998d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S chunk, reinterpret_cast<uptr>(chunk) + m.requested_size(), 1008d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S m.requested_size()); 1018d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (frontier) 1028d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S frontier->push_back(reinterpret_cast<uptr>(chunk)); 1038d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S } 1048d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S} 1058d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 1068d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// Scan thread data (stacks and TLS) for heap pointers. 1078d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Sstatic void ProcessThreads(SuspendedThreadsList const &suspended_threads, 1088d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S InternalVector<uptr> *frontier) { 1098d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S InternalScopedBuffer<uptr> registers(SuspendedThreadsList::RegisterCount()); 1108d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S uptr registers_begin = reinterpret_cast<uptr>(registers.data()); 1118d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S uptr registers_end = registers_begin + registers.size(); 1128d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S for (uptr i = 0; i < suspended_threads.thread_count(); i++) { 1138d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S uptr os_id = static_cast<uptr>(suspended_threads.GetThreadID(i)); 1148d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (flags()->log_threads) Report("Processing thread %d.\n", os_id); 1158d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S uptr stack_begin, stack_end, tls_begin, tls_end, cache_begin, cache_end; 1168d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S bool thread_found = GetThreadRangesLocked(os_id, &stack_begin, &stack_end, 1178d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S &tls_begin, &tls_end, 1188d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S &cache_begin, &cache_end); 1198d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (!thread_found) { 1208d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S // If a thread can't be found in the thread registry, it's probably in the 1218d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S // process of destruction. Log this event and move on. 1228d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (flags()->log_threads) 1238d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S Report("Thread %d not found in registry.\n", os_id); 1248d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S continue; 1258d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S } 1268d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S uptr sp; 1278d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S bool have_registers = 1288d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S (suspended_threads.GetRegistersAndSP(i, registers.data(), &sp) == 0); 1298d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (!have_registers) { 1308d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S Report("Unable to get registers from thread %d.\n"); 1318d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S // If unable to get SP, consider the entire stack to be reachable. 1328d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S sp = stack_begin; 1338d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S } 1348d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 1358d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (flags()->use_registers() && have_registers) 1368d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S ScanRangeForPointers(registers_begin, registers_end, frontier, 1378d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S "REGISTERS", kReachable); 1388d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 1398d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (flags()->use_stacks()) { 1408d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (flags()->log_threads) 1418d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S Report("Stack at %p-%p, SP = %p.\n", stack_begin, stack_end, sp); 1428d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (sp < stack_begin || sp >= stack_end) { 1438d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S // SP is outside the recorded stack range (e.g. the thread is running a 1448d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S // signal handler on alternate stack). Again, consider the entire stack 1458d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S // range to be reachable. 1468d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (flags()->log_threads) 1478d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S Report("WARNING: stack_pointer not in stack_range.\n"); 1488d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S } else { 1498d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S // Shrink the stack range to ignore out-of-scope values. 1508d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S stack_begin = sp; 1518d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S } 1528d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S ScanRangeForPointers(stack_begin, stack_end, frontier, "STACK", 1538d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S kReachable); 1548d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S } 1558d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 1568d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (flags()->use_tls()) { 1578d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (flags()->log_threads) Report("TLS at %p-%p.\n", tls_begin, tls_end); 1588d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S // Because LSan should not be loaded with dlopen(), we can assume 1598d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S // that allocator cache will be part of static TLS image. 1608d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S CHECK_LE(tls_begin, cache_begin); 1618d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S CHECK_GE(tls_end, cache_end); 1628d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (tls_begin < cache_begin) 1638d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S ScanRangeForPointers(tls_begin, cache_begin, frontier, "TLS", 1648d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S kReachable); 1658d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (tls_end > cache_end) 1668d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S ScanRangeForPointers(cache_end, tls_end, frontier, "TLS", kReachable); 1678d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S } 1688d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S } 1698d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S} 1708d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 1718d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Sstatic void FloodFillReachable(InternalVector<uptr> *frontier) { 1728d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S while (frontier->size()) { 1738d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S uptr next_chunk = frontier->back(); 1748d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S frontier->pop_back(); 1758d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S LsanMetadata m(reinterpret_cast<void *>(next_chunk)); 1768d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S ScanRangeForPointers(next_chunk, next_chunk + m.requested_size(), frontier, 1778d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S "HEAP", kReachable); 1788d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S } 1798d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S} 1808d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 1818d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// Mark leaked chunks which are reachable from other leaked chunks. 1828d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Svoid MarkIndirectlyLeakedCb::operator()(void *p) const { 1838d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S p = GetUserBegin(p); 1848d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S LsanMetadata m(p); 1858d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (m.allocated() && m.tag() != kReachable) { 1868d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S ScanRangeForPointers(reinterpret_cast<uptr>(p), 1878d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S reinterpret_cast<uptr>(p) + m.requested_size(), 1888d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S /* frontier */ 0, "HEAP", kIndirectlyLeaked); 1898d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S } 1908d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S} 1918d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 1928d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// Set the appropriate tag on each chunk. 1938d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Sstatic void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads) { 1948d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S // Holds the flood fill frontier. 1958d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S InternalVector<uptr> frontier(GetPageSizeCached()); 1968d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 1978d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (flags()->use_globals()) 1988d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S ProcessGlobalRegions(&frontier); 1998d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S ProcessThreads(suspended_threads, &frontier); 2008d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S FloodFillReachable(&frontier); 2018d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S ProcessPlatformSpecificAllocations(&frontier); 2028d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S FloodFillReachable(&frontier); 2038d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 2048d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S // Now all reachable chunks are marked. Iterate over leaked chunks and mark 2058d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S // those that are reachable from other leaked chunks. 2068d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (flags()->log_pointers) 2078d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S Report("Now scanning leaked blocks for pointers.\n"); 2088d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S ForEachChunk(MarkIndirectlyLeakedCb()); 2098d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S} 2108d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 2118d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Svoid ClearTagCb::operator()(void *p) const { 2128d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S p = GetUserBegin(p); 2138d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S LsanMetadata m(p); 2148d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S m.set_tag(kDirectlyLeaked); 2158d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S} 2168d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 2178d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Sstatic void PrintStackTraceById(u32 stack_trace_id) { 2188d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S CHECK(stack_trace_id); 2198d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S uptr size = 0; 2208d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S const uptr *trace = StackDepotGet(stack_trace_id, &size); 2218d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S StackTrace::PrintStack(trace, size, common_flags()->symbolize, 2228d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S common_flags()->strip_path_prefix, 0); 2238d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S} 2248d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 2258d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Sstatic void LockAndSuspendThreads(StopTheWorldCallback callback, void *arg) { 2268d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S LockThreadRegistry(); 2278d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S LockAllocator(); 2288d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S StopTheWorld(callback, arg); 2298d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S // Allocator must be unlocked by the callback. 2308d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S UnlockThreadRegistry(); 2318d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S} 2328d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 2338d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S///// Normal leak checking. ///// 2348d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 2358d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Svoid CollectLeaksCb::operator()(void *p) const { 2368d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S p = GetUserBegin(p); 2378d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S LsanMetadata m(p); 2388d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (!m.allocated()) return; 2398d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (m.tag() != kReachable) { 2408d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S uptr resolution = flags()->resolution; 2418d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (resolution > 0) { 2428d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S uptr size = 0; 2438d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S const uptr *trace = StackDepotGet(m.stack_trace_id(), &size); 2448d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S size = Min(size, resolution); 2458d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S leak_report_->Add(StackDepotPut(trace, size), m.requested_size(), 2468d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S m.tag()); 2478d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S } else { 2488d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S leak_report_->Add(m.stack_trace_id(), m.requested_size(), m.tag()); 2498d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S } 2508d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S } 2518d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S} 2528d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 2538d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Sstatic void CollectLeaks(LeakReport *leak_report) { 2548d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S ForEachChunk(CollectLeaksCb(leak_report)); 2558d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S} 2568d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 2578d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Svoid PrintLeakedCb::operator()(void *p) const { 2588d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S p = GetUserBegin(p); 2598d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S LsanMetadata m(p); 2608d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (!m.allocated()) return; 2618d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (m.tag() != kReachable) { 2628d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S CHECK(m.tag() == kDirectlyLeaked || m.tag() == kIndirectlyLeaked); 2638d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S Printf("%s leaked %llu byte block at %p\n", 2648d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S m.tag() == kDirectlyLeaked ? "Directly" : "Indirectly", 2658d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S m.requested_size(), p); 2668d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S } 2678d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S} 2688d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 2698d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Sstatic void PrintLeaked() { 2708d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S Printf("Reporting individual blocks:\n"); 2718d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S Printf("============================\n"); 2728d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S ForEachChunk(PrintLeakedCb()); 2738d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S Printf("\n"); 2748d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S} 2758d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 2768d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Senum LeakCheckResult { 2778d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S kFatalError, 2788d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S kLeaksFound, 2798d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S kNoLeaks 2808d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S}; 2818d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 2828d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Sstatic void DoLeakCheckCallback(const SuspendedThreadsList &suspended_threads, 2838d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S void *arg) { 2848d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S LeakCheckResult *result = reinterpret_cast<LeakCheckResult *>(arg); 2858d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S CHECK_EQ(*result, kFatalError); 2868d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S // Allocator must not be locked when we call GetRegionBegin(). 2878d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S UnlockAllocator(); 2888d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S ClassifyAllChunks(suspended_threads); 2898d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S LeakReport leak_report; 2908d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S CollectLeaks(&leak_report); 2918d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (leak_report.IsEmpty()) { 2928d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S *result = kNoLeaks; 2938d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S return; 2948d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S } 2958d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S Printf("\n"); 2968d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S Printf("=================================================================\n"); 2978d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S Report("ERROR: LeakSanitizer: detected leaks.\n"); 2988d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S leak_report.PrintLargest(flags()->max_leaks); 2998d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (flags()->report_blocks) 3008d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S PrintLeaked(); 3018d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S leak_report.PrintSummary(); 3028d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S Printf("\n"); 3038d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S ForEachChunk(ClearTagCb()); 3048d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S *result = kLeaksFound; 3058d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S} 3068d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 3078d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Svoid DoLeakCheck() { 3088d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S LeakCheckResult result = kFatalError; 3098d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S LockAndSuspendThreads(DoLeakCheckCallback, &result); 3108d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (result == kFatalError) { 3118d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S Report("LeakSanitizer has encountered a fatal error.\n"); 3128d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S Die(); 3138d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S } else if (result == kLeaksFound) { 3148d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (flags()->exitcode) 3158d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S internal__exit(flags()->exitcode); 3168d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S } 3178d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S} 3188d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 3198d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S///// Reporting of leaked blocks' addresses (for testing). ///// 3208d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 3218d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Svoid ReportLeakedCb::operator()(void *p) const { 3228d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S p = GetUserBegin(p); 3238d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S LsanMetadata m(p); 3248d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (m.allocated() && m.tag() != kReachable) 3258d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S leaked_->push_back(p); 3268d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S} 3278d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 3288d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Sstruct ReportLeakedParam { 3298d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S InternalVector<void *> *leaked; 3308d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S uptr sources; 3318d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S bool success; 3328d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S}; 3337313602decf30364e4823f6a9c34045432f0bd9fMartin Storsjo 3348d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Sstatic void ReportLeakedCallback(const SuspendedThreadsList &suspended_threads, 3358d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S void *arg) { 3368d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S // Allocator must not be locked when we call GetRegionBegin(). 3378d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S UnlockAllocator(); 3388d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S ReportLeakedParam *param = reinterpret_cast<ReportLeakedParam *>(arg); 3398d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S flags()->sources = param->sources; 3408d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S ClassifyAllChunks(suspended_threads); 3418d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S ForEachChunk(ReportLeakedCb(param->leaked)); 3428d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S ForEachChunk(ClearTagCb()); 3438d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S param->success = true; 3448d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S} 3458d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 3468d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Svoid ReportLeaked(InternalVector<void *> *leaked, uptr sources) { 3478d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S CHECK_EQ(0, leaked->size()); 3488d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S ReportLeakedParam param; 3498d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S param.leaked = leaked; 3508d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S param.success = false; 3518d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S param.sources = sources; 3528d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S LockAndSuspendThreads(ReportLeakedCallback, ¶m); 3538d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S CHECK(param.success); 3548d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S} 3558d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 3568d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S///// LeakReport implementation. ///// 3578d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 3588d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// A hard limit on the number of distinct leaks, to avoid quadratic complexity 3598d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// in LeakReport::Add(). We don't expect to ever see this many leaks in 3608d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// real-world applications. 3618d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// FIXME: Get rid of this limit by changing the implementation of LeakReport to 3628d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// use a hash table. 3638d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Sconst uptr kMaxLeaksConsidered = 1000; 3648d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 3658d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Svoid LeakReport::Add(u32 stack_trace_id, uptr leaked_size, ChunkTag tag) { 3668d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S CHECK(tag == kDirectlyLeaked || tag == kIndirectlyLeaked); 3678d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S bool is_directly_leaked = (tag == kDirectlyLeaked); 3688d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S for (uptr i = 0; i < leaks_.size(); i++) 3698d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (leaks_[i].stack_trace_id == stack_trace_id && 3708d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S leaks_[i].is_directly_leaked == is_directly_leaked) { 3718d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S leaks_[i].hit_count++; 3728d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S leaks_[i].total_size += leaked_size; 3738d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S return; 3748d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S } 3758d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (leaks_.size() == kMaxLeaksConsidered) return; 3768d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S Leak leak = { /* hit_count */ 1, leaked_size, stack_trace_id, 3778d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S is_directly_leaked }; 3788d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S leaks_.push_back(leak); 3798d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S} 3808d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 3818d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Sstatic bool IsLarger(const Leak &leak1, const Leak &leak2) { 3828d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S return leak1.total_size > leak2.total_size; 3838d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S} 3848d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S 3858d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Svoid LeakReport::PrintLargest(uptr max_leaks) { 3868d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S CHECK(leaks_.size() <= kMaxLeaksConsidered); 3878d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S Printf("\n"); 3888d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (leaks_.size() == kMaxLeaksConsidered) 3898d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S Printf("Too many leaks! Only the first %llu leaks encountered will be " 3908d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S "reported.\n", 3918d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S kMaxLeaksConsidered); 3928d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S if (max_leaks > 0 && max_leaks < leaks_.size()) 3938d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S Printf("The %llu largest leak%s:\n", max_leaks, max_leaks > 1 ? "s" : ""); 394 InternalSort(&leaks_, leaks_.size(), IsLarger); 395 max_leaks = max_leaks > 0 ? Min(max_leaks, leaks_.size()) : leaks_.size(); 396 for (uptr i = 0; i < max_leaks; i++) { 397 Printf("%s leak of %llu bytes in %llu object%s allocated from:\n", 398 leaks_[i].is_directly_leaked ? "Direct" : "Indirect", 399 leaks_[i].total_size, leaks_[i].hit_count, 400 leaks_[i].hit_count == 1 ? "" : "s"); 401 PrintStackTraceById(leaks_[i].stack_trace_id); 402 Printf("\n"); 403 } 404 if (max_leaks < leaks_.size()) { 405 uptr remaining = leaks_.size() - max_leaks; 406 Printf("Omitting %llu more leak%s.\n", remaining, 407 remaining > 1 ? "s" : ""); 408 } 409} 410 411void LeakReport::PrintSummary() { 412 CHECK(leaks_.size() <= kMaxLeaksConsidered); 413 uptr bytes_leaked = 0; 414 for (uptr i = 0; i < leaks_.size(); i++) { 415 bytes_leaked += leaks_[i].total_size; 416 } 417 Printf("SUMMARY: LeakSanitizer: %llu bytes leaked.\n", bytes_leaked); 418} 419} // namespace __lsan 420#endif // CAN_SANITIZE_LEAKS 421