lsan_common.cc revision 9bdf7802d403b53baee3433ddddc220f457e039c
1ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev//=-- lsan_common.cc ------------------------------------------------------===// 2ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev// 3ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev// The LLVM Compiler Infrastructure 4ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev// 5ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev// This file is distributed under the University of Illinois Open Source 6ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev// License. See LICENSE.TXT for details. 7ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev// 8ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev//===----------------------------------------------------------------------===// 9ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev// 10ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev// This file is a part of LeakSanitizer. 11ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev// Implementation of common leak checking functionality. 12ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev// 13ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev//===----------------------------------------------------------------------===// 14ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 15ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev#include "lsan_common.h" 16ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 17ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev#include "sanitizer_common/sanitizer_common.h" 18ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev#include "sanitizer_common/sanitizer_flags.h" 19ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev#include "sanitizer_common/sanitizer_stackdepot.h" 20ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev#include "sanitizer_common/sanitizer_stacktrace.h" 21ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev#include "sanitizer_common/sanitizer_stoptheworld.h" 22ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 23ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevnamespace __lsan { 249bdf7802d403b53baee3433ddddc220f457e039cSergey Matveev#if CAN_SANITIZE_LEAKS 25ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey MatveevFlags lsan_flags; 26ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 27ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevstatic void InitializeFlags() { 28ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev Flags *f = flags(); 29ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // Default values. 30ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev f->sources = kSourceAllAligned; 31ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev f->report_blocks = false; 32ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev f->resolution = 0; 33ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev f->max_leaks = 0; 34ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev f->log_pointers = false; 35ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev f->log_threads = false; 36ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 37ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev const char *options = GetEnv("LSAN_OPTIONS"); 38ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (options) { 39ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev bool aligned = true; 40ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ParseFlag(options, &aligned, "aligned"); 41ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (!aligned) f->sources |= kSourceUnaligned; 42ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ParseFlag(options, &f->report_blocks, "report_blocks"); 43ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ParseFlag(options, &f->resolution, "resolution"); 44ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev CHECK_GE(&f->resolution, 0); 45ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ParseFlag(options, &f->max_leaks, "max_leaks"); 46ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev CHECK_GE(&f->max_leaks, 0); 47ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ParseFlag(options, &f->log_pointers, "log_pointers"); 48ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ParseFlag(options, &f->log_threads, "log_threads"); 49ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 50ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 51ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 52ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevvoid InitCommonLsan() { 53ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev InitializeFlags(); 54ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev InitializePlatformSpecificModules(); 55ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 56ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 57ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevstatic inline bool CanBeAHeapPointer(uptr p) { 58ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // Since our heap is located in mmap-ed memory, we can assume a sensible lower 59ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // boundary on heap addresses. 60ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev const uptr kMinAddress = 4 * 4096; 61ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (p < kMinAddress) return false; 62ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev#ifdef __x86_64__ 63ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // Accept only canonical form user-space addresses. 64ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev return ((p >> 47) == 0); 65ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev#else 66ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev return true; 67ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev#endif 68ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 69ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 70ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev// Scan the memory range, looking for byte patterns that point into allocator 71ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev// chunks. Mark those chunks with tag and add them to the frontier. 72ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev// There are two usage modes for this function: finding non-leaked chunks 73ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev// (tag = kReachable) and finding indirectly leaked chunks 74ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev// (tag = kIndirectlyLeaked). In the second case, there's no flood fill, 75ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev// so frontier = 0. 76ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevvoid ScanRangeForPointers(uptr begin, uptr end, InternalVector<uptr> *frontier, 77ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev const char *region_type, ChunkTag tag) { 78ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev const uptr alignment = flags()->pointer_alignment(); 79ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (flags()->log_pointers) 80ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev Report("Scanning %s range %p-%p.\n", region_type, begin, end); 81ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev uptr pp = begin; 82ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (pp % alignment) 83ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev pp = pp + alignment - pp % alignment; 84ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev for (; pp + sizeof(uptr) <= end; pp += alignment) { 85ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev void *p = *reinterpret_cast<void**>(pp); 86ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (!CanBeAHeapPointer(reinterpret_cast<uptr>(p))) continue; 87ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // FIXME: PointsIntoChunk is SLOW because GetBlockBegin() in 88ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // LargeMmapAllocator involves a lock and a linear search. 89ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev void *chunk = PointsIntoChunk(p); 90ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (!chunk) continue; 91ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev LsanMetadata m(chunk); 92ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (m.tag() == kReachable) continue; 93ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev m.set_tag(tag); 94ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (flags()->log_pointers) 95ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev Report("%p: found %p pointing into chunk %p-%p of size %llu.\n", pp, p, 96ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev chunk, reinterpret_cast<uptr>(chunk) + m.requested_size(), 97ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev m.requested_size()); 98ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (frontier) 99ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev frontier->push_back(reinterpret_cast<uptr>(chunk)); 100ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 101ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 102ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 103ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev// Scan thread data (stacks and TLS) for heap pointers. 104ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevstatic void ProcessThreads(SuspendedThreadsList const &suspended_threads, 105ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev InternalVector<uptr> *frontier) { 106ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev InternalScopedBuffer<uptr> registers(SuspendedThreadsList::RegisterCount()); 107ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev uptr registers_begin = reinterpret_cast<uptr>(registers.data()); 108ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev uptr registers_end = registers_begin + registers.size(); 109ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev for (uptr i = 0; i < suspended_threads.thread_count(); i++) { 110ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev uptr os_id = static_cast<uptr>(suspended_threads.GetThreadID(i)); 111ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (flags()->log_threads) Report("Processing thread %d.\n", os_id); 112ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev uptr stack_begin, stack_end, tls_begin, tls_end, cache_begin, cache_end; 113ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev bool thread_found = GetThreadRangesLocked(os_id, &stack_begin, &stack_end, 114ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev &tls_begin, &tls_end, 115ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev &cache_begin, &cache_end); 116ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (!thread_found) { 117ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // If a thread can't be found in the thread registry, it's probably in the 118ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // process of destruction. Log this event and move on. 119ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (flags()->log_threads) 120ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev Report("Thread %d not found in registry.\n", os_id); 121ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev continue; 122ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 123ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev uptr sp; 124ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev bool have_registers = 125ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev (suspended_threads.GetRegistersAndSP(i, registers.data(), &sp) == 0); 126ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (!have_registers) { 127ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev Report("Unable to get registers from thread %d.\n"); 128ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // If unable to get SP, consider the entire stack to be reachable. 129ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev sp = stack_begin; 130ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 131ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 132ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (flags()->use_registers() && have_registers) 133ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ScanRangeForPointers(registers_begin, registers_end, frontier, 134ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev "REGISTERS", kReachable); 135ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 136ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (flags()->use_stacks()) { 137ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (flags()->log_threads) 138ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev Report("Stack at %p-%p, SP = %p.\n", stack_begin, stack_end, sp); 139ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (sp < stack_begin || sp >= stack_end) { 140ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // SP is outside the recorded stack range (e.g. the thread is running a 141ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // signal handler on alternate stack). Again, consider the entire stack 142ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // range to be reachable. 143ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (flags()->log_threads) 144ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev Report("WARNING: stack_pointer not in stack_range.\n"); 145ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } else { 146ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // Shrink the stack range to ignore out-of-scope values. 147ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev stack_begin = sp; 148ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 149ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ScanRangeForPointers(stack_begin, stack_end, frontier, "STACK", 150ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev kReachable); 151ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 152ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 153ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (flags()->use_tls()) { 154ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (flags()->log_threads) Report("TLS at %p-%p.\n", tls_begin, tls_end); 155ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // Because LSan should not be loaded with dlopen(), we can assume 156ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // that allocator cache will be part of static TLS image. 157ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev CHECK_LE(tls_begin, cache_begin); 158ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev CHECK_GE(tls_end, cache_end); 159ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (tls_begin < cache_begin) 160ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ScanRangeForPointers(tls_begin, cache_begin, frontier, "TLS", 161ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev kReachable); 162ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (tls_end > cache_end) 163ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ScanRangeForPointers(cache_end, tls_end, frontier, "TLS", kReachable); 164ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 165ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 166ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 167ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 168ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevstatic void FloodFillReachable(InternalVector<uptr> *frontier) { 169ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev while (frontier->size()) { 170ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev uptr next_chunk = frontier->back(); 171ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev frontier->pop_back(); 172ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev LsanMetadata m(reinterpret_cast<void *>(next_chunk)); 173ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ScanRangeForPointers(next_chunk, next_chunk + m.requested_size(), frontier, 174ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev "HEAP", kReachable); 175ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 176ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 177ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 178ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev// Mark leaked chunks which are reachable from other leaked chunks. 179ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevvoid MarkIndirectlyLeakedCb::operator()(void *p) const { 18029b756851c04df07f1584dfd77021dd2f37a7391Sergey Matveev p = GetUserBegin(p); 181ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev LsanMetadata m(p); 182ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (m.allocated() && m.tag() != kReachable) { 183ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ScanRangeForPointers(reinterpret_cast<uptr>(p), 184ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev reinterpret_cast<uptr>(p) + m.requested_size(), 185ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev /* frontier */ 0, "HEAP", kIndirectlyLeaked); 186ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 187ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 188ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 189ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev// Set the appropriate tag on each chunk. 190ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevstatic void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads) { 191ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // Holds the flood fill frontier. 192ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev InternalVector<uptr> frontier(GetPageSizeCached()); 193ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 194ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (flags()->use_globals()) 195ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ProcessGlobalRegions(&frontier); 196ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ProcessThreads(suspended_threads, &frontier); 197ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev FloodFillReachable(&frontier); 198ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ProcessPlatformSpecificAllocations(&frontier); 199ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev FloodFillReachable(&frontier); 200ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 201ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // Now all reachable chunks are marked. Iterate over leaked chunks and mark 202ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // those that are reachable from other leaked chunks. 203ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (flags()->log_pointers) 204ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev Report("Now scanning leaked blocks for pointers.\n"); 205ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ForEachChunk(MarkIndirectlyLeakedCb()); 206ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 207ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 208ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevvoid ClearTagCb::operator()(void *p) const { 20929b756851c04df07f1584dfd77021dd2f37a7391Sergey Matveev p = GetUserBegin(p); 210ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev LsanMetadata m(p); 211ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev m.set_tag(kDirectlyLeaked); 212ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 213ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 214ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevstatic void PrintStackTraceById(u32 stack_trace_id) { 215ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev CHECK(stack_trace_id); 216ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev uptr size = 0; 217ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev const uptr *trace = StackDepotGet(stack_trace_id, &size); 218ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev StackTrace::PrintStack(trace, size, common_flags()->symbolize, 219ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev common_flags()->strip_path_prefix, 0); 220ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 221ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 222ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevstatic void LockAndSuspendThreads(StopTheWorldCallback callback, void *arg) { 223ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev LockThreadRegistry(); 224ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev LockAllocator(); 225ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev StopTheWorld(callback, arg); 226ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // Allocator must be unlocked by the callback. 227ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev UnlockThreadRegistry(); 228ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 229ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 230ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev///// Normal leak checking. ///// 231ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 232ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevvoid CollectLeaksCb::operator()(void *p) const { 23329b756851c04df07f1584dfd77021dd2f37a7391Sergey Matveev p = GetUserBegin(p); 234ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev LsanMetadata m(p); 235ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (!m.allocated()) return; 236ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (m.tag() != kReachable) { 237ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev uptr resolution = flags()->resolution; 238ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (resolution > 0) { 239ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev uptr size = 0; 240ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev const uptr *trace = StackDepotGet(m.stack_trace_id(), &size); 241ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev size = Min(size, resolution); 242ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev leak_report_->Add(StackDepotPut(trace, size), m.requested_size(), 243ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev m.tag()); 244ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } else { 245ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev leak_report_->Add(m.stack_trace_id(), m.requested_size(), m.tag()); 246ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 247ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 248ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 249ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 250ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevstatic void CollectLeaks(LeakReport *leak_report) { 251ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ForEachChunk(CollectLeaksCb(leak_report)); 252ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 253ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 254ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevvoid PrintLeakedCb::operator()(void *p) const { 25529b756851c04df07f1584dfd77021dd2f37a7391Sergey Matveev p = GetUserBegin(p); 256ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev LsanMetadata m(p); 257ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (!m.allocated()) return; 258ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (m.tag() != kReachable) { 259ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev CHECK(m.tag() == kDirectlyLeaked || m.tag() == kIndirectlyLeaked); 260ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev Printf("%s leaked %llu byte block at %p\n", 261ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev m.tag() == kDirectlyLeaked ? "Directly" : "Indirectly", 262ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev m.requested_size(), p); 263ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 264ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 265ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 266ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevstatic void PrintLeaked() { 267ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev Printf("\nReporting individual blocks:\n"); 268ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ForEachChunk(PrintLeakedCb()); 269ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 270ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 271ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevstatic void DoLeakCheckCallback(const SuspendedThreadsList &suspended_threads, 272ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev void *arg) { 273ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // Allocator must not be locked when we call GetRegionBegin(). 274ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev UnlockAllocator(); 275ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev bool *success = reinterpret_cast<bool *>(arg); 276ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ClassifyAllChunks(suspended_threads); 277ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev LeakReport leak_report; 278ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev CollectLeaks(&leak_report); 279ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (!leak_report.IsEmpty()) { 280ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev leak_report.PrintLargest(flags()->max_leaks); 281ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (flags()->report_blocks) 282ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev PrintLeaked(); 283ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 284ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ForEachChunk(ClearTagCb()); 285ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev *success = true; 286ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 287ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 288ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevvoid DoLeakCheck() { 289ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev bool success = false; 290ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev LockAndSuspendThreads(DoLeakCheckCallback, &success); 291ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (!success) 292ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev Report("Leak check failed!\n"); 293ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 294ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 295ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev///// Reporting of leaked blocks' addresses (for testing). ///// 296ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 297ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevvoid ReportLeakedCb::operator()(void *p) const { 29829b756851c04df07f1584dfd77021dd2f37a7391Sergey Matveev p = GetUserBegin(p); 299ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev LsanMetadata m(p); 300ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (m.allocated() && m.tag() != kReachable) 301ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev leaked_->push_back(p); 302ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 303ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 304ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevstruct ReportLeakedParam { 305ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev InternalVector<void *> *leaked; 306ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev uptr sources; 307ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev bool success; 308ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev}; 309ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 310ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevstatic void ReportLeakedCallback(const SuspendedThreadsList &suspended_threads, 311ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev void *arg) { 312ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // Allocator must not be locked when we call GetRegionBegin(). 313ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev UnlockAllocator(); 314ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ReportLeakedParam *param = reinterpret_cast<ReportLeakedParam *>(arg); 315ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev flags()->sources = param->sources; 316ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ClassifyAllChunks(suspended_threads); 317ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ForEachChunk(ReportLeakedCb(param->leaked)); 318ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ForEachChunk(ClearTagCb()); 319ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev param->success = true; 320ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 321ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 322ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevvoid ReportLeaked(InternalVector<void *> *leaked, uptr sources) { 323ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev CHECK_EQ(0, leaked->size()); 324ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ReportLeakedParam param; 325ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev param.leaked = leaked; 326ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev param.success = false; 327ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev param.sources = sources; 328ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev LockAndSuspendThreads(ReportLeakedCallback, ¶m); 329ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev CHECK(param.success); 330ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 331ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 332ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev///// LeakReport implementation. ///// 333ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 334ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev// A hard limit on the number of distinct leaks, to avoid quadratic complexity 335ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev// in LeakReport::Add(). We don't expect to ever see this many leaks in 336ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev// real-world applications. 337ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev// FIXME: Get rid of this limit by changing the implementation of LeakReport to 338ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev// use a hash table. 339ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevconst uptr kMaxLeaksConsidered = 1000; 340ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 341ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevvoid LeakReport::Add(u32 stack_trace_id, uptr leaked_size, ChunkTag tag) { 342ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev CHECK(tag == kDirectlyLeaked || tag == kIndirectlyLeaked); 343ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev bool is_directly_leaked = (tag == kDirectlyLeaked); 344ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev for (uptr i = 0; i < leaks_.size(); i++) 345ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (leaks_[i].stack_trace_id == stack_trace_id && 346ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev leaks_[i].is_directly_leaked == is_directly_leaked) { 347ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev leaks_[i].hit_count++; 348ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev leaks_[i].total_size += leaked_size; 349ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev return; 350ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 351ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (leaks_.size() == kMaxLeaksConsidered) return; 352ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev Leak leak = { /* hit_count */ 1, leaked_size, stack_trace_id, 353ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev is_directly_leaked }; 354ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev leaks_.push_back(leak); 355ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 356ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 357ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevstatic bool IsLarger(const Leak &leak1, const Leak &leak2) { 358ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev return leak1.total_size > leak2.total_size; 359ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 360ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 361ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevvoid LeakReport::PrintLargest(uptr max_leaks) { 362ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev CHECK(leaks_.size() <= kMaxLeaksConsidered); 363ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev Printf("\n"); 364ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (leaks_.size() == kMaxLeaksConsidered) 365ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev Printf("Too many leaks! Only the first %llu leaks encountered will be " 366ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev "reported.\n", 367ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev kMaxLeaksConsidered); 368ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (max_leaks > 0 && max_leaks < leaks_.size()) 369ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev Printf("The %llu largest leak%s:\n", max_leaks, max_leaks > 1 ? "s" : ""); 370ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev InternalSort(&leaks_, leaks_.size(), IsLarger); 371ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev max_leaks = max_leaks > 0 ? Min(max_leaks, leaks_.size()) : leaks_.size(); 372ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev for (uptr i = 0; i < max_leaks; i++) { 373ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev Printf("\n%s leak of %llu bytes in %llu objects allocated from:\n", 374ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev leaks_[i].is_directly_leaked ? "Direct" : "Indirect", 375ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev leaks_[i].total_size, leaks_[i].hit_count); 376ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev PrintStackTraceById(leaks_[i].stack_trace_id); 377ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 378ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (max_leaks < leaks_.size()) { 379ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev uptr remaining = leaks_.size() - max_leaks; 380ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev Printf("\nOmitting %llu more leak%s.\n", remaining, 381ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev remaining > 1 ? "s" : ""); 382ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 383ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 3849bdf7802d403b53baee3433ddddc220f457e039cSergey Matveev#else // CAN_SANITIZE_LEAKS 3859bdf7802d403b53baee3433ddddc220f457e039cSergey Matveevvoid InitCommonLsan() {} 3869bdf7802d403b53baee3433ddddc220f457e039cSergey Matveevvoid DoLeakCheck() {} 3879bdf7802d403b53baee3433ddddc220f457e039cSergey Matveev#endif // CAN_SANITIZE_LEAKS 388ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} // namespace __lsan 389