lsan_common.cc revision 5e719a705666988781b9735d62cafc808ade60e2
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 239bdf7802d403b53baee3433ddddc220f457e039cSergey Matveev#if CAN_SANITIZE_LEAKS 240bc81775b75f2c8c6c8c0e1af4008771d5b882abSergey Matveevnamespace __lsan { 250bc81775b75f2c8c6c8c0e1af4008771d5b882abSergey Matveev 26ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey MatveevFlags lsan_flags; 27ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 28ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevstatic void InitializeFlags() { 29ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev Flags *f = flags(); 30ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // Default values. 31ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev f->report_blocks = false; 32ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev f->resolution = 0; 33ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev f->max_leaks = 0; 34969b529914f5bc17e4810076dccbaadf563d584cSergey Matveev f->exitcode = 23; 35ebe3a3608be122e799e264931f9cecf4cbc84eddSergey Matveev f->use_registers = true; 36ebe3a3608be122e799e264931f9cecf4cbc84eddSergey Matveev f->use_globals = true; 37ebe3a3608be122e799e264931f9cecf4cbc84eddSergey Matveev f->use_stacks = true; 38ebe3a3608be122e799e264931f9cecf4cbc84eddSergey Matveev f->use_tls = true; 39ebe3a3608be122e799e264931f9cecf4cbc84eddSergey Matveev f->use_unaligned = false; 40ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev f->log_pointers = false; 41ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev f->log_threads = false; 42ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 43ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev const char *options = GetEnv("LSAN_OPTIONS"); 44ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (options) { 45ebe3a3608be122e799e264931f9cecf4cbc84eddSergey Matveev ParseFlag(options, &f->use_registers, "use_registers"); 46ebe3a3608be122e799e264931f9cecf4cbc84eddSergey Matveev ParseFlag(options, &f->use_globals, "use_globals"); 47ebe3a3608be122e799e264931f9cecf4cbc84eddSergey Matveev ParseFlag(options, &f->use_stacks, "use_stacks"); 48ebe3a3608be122e799e264931f9cecf4cbc84eddSergey Matveev ParseFlag(options, &f->use_tls, "use_tls"); 49ebe3a3608be122e799e264931f9cecf4cbc84eddSergey Matveev ParseFlag(options, &f->use_unaligned, "use_unaligned"); 50ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ParseFlag(options, &f->report_blocks, "report_blocks"); 51ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ParseFlag(options, &f->resolution, "resolution"); 52ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev CHECK_GE(&f->resolution, 0); 53ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ParseFlag(options, &f->max_leaks, "max_leaks"); 54ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev CHECK_GE(&f->max_leaks, 0); 55ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ParseFlag(options, &f->log_pointers, "log_pointers"); 56ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ParseFlag(options, &f->log_threads, "log_threads"); 57969b529914f5bc17e4810076dccbaadf563d584cSergey Matveev ParseFlag(options, &f->exitcode, "exitcode"); 58ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 59ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 60ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 61ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevvoid InitCommonLsan() { 62ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev InitializeFlags(); 63ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev InitializePlatformSpecificModules(); 64ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 65ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 66ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevstatic inline bool CanBeAHeapPointer(uptr p) { 67ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // Since our heap is located in mmap-ed memory, we can assume a sensible lower 68ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // boundary on heap addresses. 69ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev const uptr kMinAddress = 4 * 4096; 70ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (p < kMinAddress) return false; 71ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev#ifdef __x86_64__ 72ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // Accept only canonical form user-space addresses. 73ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev return ((p >> 47) == 0); 74ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev#else 75ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev return true; 76ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev#endif 77ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 78ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 79ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev// Scan the memory range, looking for byte patterns that point into allocator 80ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev// chunks. Mark those chunks with tag and add them to the frontier. 815e719a705666988781b9735d62cafc808ade60e2Sergey Matveev// There are two usage modes for this function: finding reachable or suppressed 825e719a705666988781b9735d62cafc808ade60e2Sergey Matveev// chunks (tag = kReachable or kSuppressed) and finding indirectly leaked chunks 83ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev// (tag = kIndirectlyLeaked). In the second case, there's no flood fill, 84ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev// so frontier = 0. 85ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevvoid ScanRangeForPointers(uptr begin, uptr end, InternalVector<uptr> *frontier, 86ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev const char *region_type, ChunkTag tag) { 87ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev const uptr alignment = flags()->pointer_alignment(); 88ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (flags()->log_pointers) 89ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev Report("Scanning %s range %p-%p.\n", region_type, begin, end); 90ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev uptr pp = begin; 91ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (pp % alignment) 92ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev pp = pp + alignment - pp % alignment; 93ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev for (; pp + sizeof(uptr) <= end; pp += alignment) { 94ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev void *p = *reinterpret_cast<void**>(pp); 95ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (!CanBeAHeapPointer(reinterpret_cast<uptr>(p))) continue; 96ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev void *chunk = PointsIntoChunk(p); 97ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (!chunk) continue; 98ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev LsanMetadata m(chunk); 995e719a705666988781b9735d62cafc808ade60e2Sergey Matveev // Reachable beats suppressed beats leaked. 100ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (m.tag() == kReachable) continue; 1015e719a705666988781b9735d62cafc808ade60e2Sergey Matveev if (m.tag() == kSuppressed && tag != kReachable) continue; 102ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev m.set_tag(tag); 103ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (flags()->log_pointers) 104ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev Report("%p: found %p pointing into chunk %p-%p of size %llu.\n", pp, p, 105ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev chunk, reinterpret_cast<uptr>(chunk) + m.requested_size(), 106ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev m.requested_size()); 107ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (frontier) 108ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev frontier->push_back(reinterpret_cast<uptr>(chunk)); 109ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 110ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 111ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 112ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev// Scan thread data (stacks and TLS) for heap pointers. 113ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevstatic void ProcessThreads(SuspendedThreadsList const &suspended_threads, 114ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev InternalVector<uptr> *frontier) { 115ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev InternalScopedBuffer<uptr> registers(SuspendedThreadsList::RegisterCount()); 116ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev uptr registers_begin = reinterpret_cast<uptr>(registers.data()); 117ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev uptr registers_end = registers_begin + registers.size(); 118ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev for (uptr i = 0; i < suspended_threads.thread_count(); i++) { 119ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev uptr os_id = static_cast<uptr>(suspended_threads.GetThreadID(i)); 120ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (flags()->log_threads) Report("Processing thread %d.\n", os_id); 121ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev uptr stack_begin, stack_end, tls_begin, tls_end, cache_begin, cache_end; 122ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev bool thread_found = GetThreadRangesLocked(os_id, &stack_begin, &stack_end, 123ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev &tls_begin, &tls_end, 124ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev &cache_begin, &cache_end); 125ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (!thread_found) { 126ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // If a thread can't be found in the thread registry, it's probably in the 127ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // process of destruction. Log this event and move on. 128ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (flags()->log_threads) 129ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev Report("Thread %d not found in registry.\n", os_id); 130ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev continue; 131ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 132ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev uptr sp; 133ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev bool have_registers = 134ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev (suspended_threads.GetRegistersAndSP(i, registers.data(), &sp) == 0); 135ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (!have_registers) { 136ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev Report("Unable to get registers from thread %d.\n"); 137ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // If unable to get SP, consider the entire stack to be reachable. 138ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev sp = stack_begin; 139ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 140ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 141ebe3a3608be122e799e264931f9cecf4cbc84eddSergey Matveev if (flags()->use_registers && have_registers) 142ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ScanRangeForPointers(registers_begin, registers_end, frontier, 143ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev "REGISTERS", kReachable); 144ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 145ebe3a3608be122e799e264931f9cecf4cbc84eddSergey Matveev if (flags()->use_stacks) { 146ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (flags()->log_threads) 147ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev Report("Stack at %p-%p, SP = %p.\n", stack_begin, stack_end, sp); 148ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (sp < stack_begin || sp >= stack_end) { 149ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // SP is outside the recorded stack range (e.g. the thread is running a 150ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // signal handler on alternate stack). Again, consider the entire stack 151ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // range to be reachable. 152ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (flags()->log_threads) 153ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev Report("WARNING: stack_pointer not in stack_range.\n"); 154ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } else { 155ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // Shrink the stack range to ignore out-of-scope values. 156ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev stack_begin = sp; 157ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 158ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ScanRangeForPointers(stack_begin, stack_end, frontier, "STACK", 159ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev kReachable); 160ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 161ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 162ebe3a3608be122e799e264931f9cecf4cbc84eddSergey Matveev if (flags()->use_tls) { 163ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (flags()->log_threads) Report("TLS at %p-%p.\n", tls_begin, tls_end); 164f5a9ace4904e9daf3d962274cbbcb702ebc5450eSergey Matveev if (cache_begin == cache_end) { 165f5a9ace4904e9daf3d962274cbbcb702ebc5450eSergey Matveev ScanRangeForPointers(tls_begin, tls_end, frontier, "TLS", kReachable); 166f5a9ace4904e9daf3d962274cbbcb702ebc5450eSergey Matveev } else { 167f5a9ace4904e9daf3d962274cbbcb702ebc5450eSergey Matveev // Because LSan should not be loaded with dlopen(), we can assume 168f5a9ace4904e9daf3d962274cbbcb702ebc5450eSergey Matveev // that allocator cache will be part of static TLS image. 169f5a9ace4904e9daf3d962274cbbcb702ebc5450eSergey Matveev CHECK_LE(tls_begin, cache_begin); 170f5a9ace4904e9daf3d962274cbbcb702ebc5450eSergey Matveev CHECK_GE(tls_end, cache_end); 171f5a9ace4904e9daf3d962274cbbcb702ebc5450eSergey Matveev if (tls_begin < cache_begin) 172f5a9ace4904e9daf3d962274cbbcb702ebc5450eSergey Matveev ScanRangeForPointers(tls_begin, cache_begin, frontier, "TLS", 173f5a9ace4904e9daf3d962274cbbcb702ebc5450eSergey Matveev kReachable); 174f5a9ace4904e9daf3d962274cbbcb702ebc5450eSergey Matveev if (tls_end > cache_end) 175f5a9ace4904e9daf3d962274cbbcb702ebc5450eSergey Matveev ScanRangeForPointers(cache_end, tls_end, frontier, "TLS", kReachable); 176f5a9ace4904e9daf3d962274cbbcb702ebc5450eSergey Matveev } 177ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 178ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 179ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 180ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 1815e719a705666988781b9735d62cafc808ade60e2Sergey Matveevstatic void FloodFillTag(InternalVector<uptr> *frontier, ChunkTag tag) { 182ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev while (frontier->size()) { 183ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev uptr next_chunk = frontier->back(); 184ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev frontier->pop_back(); 185ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev LsanMetadata m(reinterpret_cast<void *>(next_chunk)); 186ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ScanRangeForPointers(next_chunk, next_chunk + m.requested_size(), frontier, 1875e719a705666988781b9735d62cafc808ade60e2Sergey Matveev "HEAP", tag); 188ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 189ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 190ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 191ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev// Mark leaked chunks which are reachable from other leaked chunks. 192ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevvoid MarkIndirectlyLeakedCb::operator()(void *p) const { 19329b756851c04df07f1584dfd77021dd2f37a7391Sergey Matveev p = GetUserBegin(p); 194ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev LsanMetadata m(p); 195ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (m.allocated() && m.tag() != kReachable) { 196ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ScanRangeForPointers(reinterpret_cast<uptr>(p), 197ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev reinterpret_cast<uptr>(p) + m.requested_size(), 198ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev /* frontier */ 0, "HEAP", kIndirectlyLeaked); 199ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 200ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 201ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 2025e719a705666988781b9735d62cafc808ade60e2Sergey Matveevvoid CollectSuppressedCb::operator()(void *p) const { 2035e719a705666988781b9735d62cafc808ade60e2Sergey Matveev p = GetUserBegin(p); 2045e719a705666988781b9735d62cafc808ade60e2Sergey Matveev LsanMetadata m(p); 2055e719a705666988781b9735d62cafc808ade60e2Sergey Matveev if (m.allocated() && m.tag() == kSuppressed) 2065e719a705666988781b9735d62cafc808ade60e2Sergey Matveev frontier_->push_back(reinterpret_cast<uptr>(p)); 2075e719a705666988781b9735d62cafc808ade60e2Sergey Matveev} 2085e719a705666988781b9735d62cafc808ade60e2Sergey Matveev 209ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev// Set the appropriate tag on each chunk. 210ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevstatic void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads) { 211ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // Holds the flood fill frontier. 212ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev InternalVector<uptr> frontier(GetPageSizeCached()); 213ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 214ebe3a3608be122e799e264931f9cecf4cbc84eddSergey Matveev if (flags()->use_globals) 215ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ProcessGlobalRegions(&frontier); 216ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ProcessThreads(suspended_threads, &frontier); 2175e719a705666988781b9735d62cafc808ade60e2Sergey Matveev FloodFillTag(&frontier, kReachable); 2185e719a705666988781b9735d62cafc808ade60e2Sergey Matveev // The check here is relatively expensive, so we do this in a separate flood 2195e719a705666988781b9735d62cafc808ade60e2Sergey Matveev // fill. That way we can skip the check for chunks that are reachable 2205e719a705666988781b9735d62cafc808ade60e2Sergey Matveev // otherwise. 221ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ProcessPlatformSpecificAllocations(&frontier); 2225e719a705666988781b9735d62cafc808ade60e2Sergey Matveev FloodFillTag(&frontier, kReachable); 223ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 224ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (flags()->log_pointers) 2255e719a705666988781b9735d62cafc808ade60e2Sergey Matveev Report("Scanning suppressed blocks.\n"); 2265e719a705666988781b9735d62cafc808ade60e2Sergey Matveev CHECK_EQ(0, frontier.size()); 2275e719a705666988781b9735d62cafc808ade60e2Sergey Matveev ForEachChunk(CollectSuppressedCb(&frontier)); 2285e719a705666988781b9735d62cafc808ade60e2Sergey Matveev FloodFillTag(&frontier, kSuppressed); 229ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 2305e719a705666988781b9735d62cafc808ade60e2Sergey Matveev // Iterate over leaked chunks and mark those that are reachable from other 2315e719a705666988781b9735d62cafc808ade60e2Sergey Matveev // leaked chunks. 2325e719a705666988781b9735d62cafc808ade60e2Sergey Matveev if (flags()->log_pointers) 2335e719a705666988781b9735d62cafc808ade60e2Sergey Matveev Report("Scanning leaked blocks.\n"); 2345e719a705666988781b9735d62cafc808ade60e2Sergey Matveev ForEachChunk(MarkIndirectlyLeakedCb()); 235ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 236ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 237ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevstatic void PrintStackTraceById(u32 stack_trace_id) { 238ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev CHECK(stack_trace_id); 239ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev uptr size = 0; 240ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev const uptr *trace = StackDepotGet(stack_trace_id, &size); 241ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev StackTrace::PrintStack(trace, size, common_flags()->symbolize, 242ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev common_flags()->strip_path_prefix, 0); 243ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 244ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 245ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevvoid CollectLeaksCb::operator()(void *p) const { 24629b756851c04df07f1584dfd77021dd2f37a7391Sergey Matveev p = GetUserBegin(p); 247ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev LsanMetadata m(p); 248ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (!m.allocated()) return; 2495e719a705666988781b9735d62cafc808ade60e2Sergey Matveev if (m.tag() == kDirectlyLeaked || m.tag() == kIndirectlyLeaked) { 250ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev uptr resolution = flags()->resolution; 251ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (resolution > 0) { 252ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev uptr size = 0; 253ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev const uptr *trace = StackDepotGet(m.stack_trace_id(), &size); 254ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev size = Min(size, resolution); 255ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev leak_report_->Add(StackDepotPut(trace, size), m.requested_size(), 256ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev m.tag()); 257ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } else { 258ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev leak_report_->Add(m.stack_trace_id(), m.requested_size(), m.tag()); 259ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 260ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 261ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 262ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 263ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevstatic void CollectLeaks(LeakReport *leak_report) { 264ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ForEachChunk(CollectLeaksCb(leak_report)); 265ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 266ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 267ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevvoid PrintLeakedCb::operator()(void *p) const { 26829b756851c04df07f1584dfd77021dd2f37a7391Sergey Matveev p = GetUserBegin(p); 269ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev LsanMetadata m(p); 270ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (!m.allocated()) return; 2715e719a705666988781b9735d62cafc808ade60e2Sergey Matveev if (m.tag() == kDirectlyLeaked || m.tag() == kIndirectlyLeaked) { 272ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev Printf("%s leaked %llu byte block at %p\n", 273ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev m.tag() == kDirectlyLeaked ? "Directly" : "Indirectly", 274ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev m.requested_size(), p); 275ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 276ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 277ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 278ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevstatic void PrintLeaked() { 2796c3634b1d5eeb0bffea01df10caa7168c48c8c5dSergey Matveev Printf("Reporting individual blocks:\n"); 2806c3634b1d5eeb0bffea01df10caa7168c48c8c5dSergey Matveev Printf("============================\n"); 281ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ForEachChunk(PrintLeakedCb()); 2826c3634b1d5eeb0bffea01df10caa7168c48c8c5dSergey Matveev Printf("\n"); 283ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 284ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 285969b529914f5bc17e4810076dccbaadf563d584cSergey Matveevenum LeakCheckResult { 286969b529914f5bc17e4810076dccbaadf563d584cSergey Matveev kFatalError, 287969b529914f5bc17e4810076dccbaadf563d584cSergey Matveev kLeaksFound, 288969b529914f5bc17e4810076dccbaadf563d584cSergey Matveev kNoLeaks 289969b529914f5bc17e4810076dccbaadf563d584cSergey Matveev}; 290969b529914f5bc17e4810076dccbaadf563d584cSergey Matveev 291ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevstatic void DoLeakCheckCallback(const SuspendedThreadsList &suspended_threads, 292ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev void *arg) { 293969b529914f5bc17e4810076dccbaadf563d584cSergey Matveev LeakCheckResult *result = reinterpret_cast<LeakCheckResult *>(arg); 294969b529914f5bc17e4810076dccbaadf563d584cSergey Matveev CHECK_EQ(*result, kFatalError); 295ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ClassifyAllChunks(suspended_threads); 296ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev LeakReport leak_report; 297ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev CollectLeaks(&leak_report); 298969b529914f5bc17e4810076dccbaadf563d584cSergey Matveev if (leak_report.IsEmpty()) { 299969b529914f5bc17e4810076dccbaadf563d584cSergey Matveev *result = kNoLeaks; 300969b529914f5bc17e4810076dccbaadf563d584cSergey Matveev return; 301ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 3026c3634b1d5eeb0bffea01df10caa7168c48c8c5dSergey Matveev Printf("\n"); 3036c3634b1d5eeb0bffea01df10caa7168c48c8c5dSergey Matveev Printf("=================================================================\n"); 304ebe3a3608be122e799e264931f9cecf4cbc84eddSergey Matveev Report("ERROR: LeakSanitizer: detected memory leaks\n"); 305969b529914f5bc17e4810076dccbaadf563d584cSergey Matveev leak_report.PrintLargest(flags()->max_leaks); 306969b529914f5bc17e4810076dccbaadf563d584cSergey Matveev if (flags()->report_blocks) 307969b529914f5bc17e4810076dccbaadf563d584cSergey Matveev PrintLeaked(); 3086c3634b1d5eeb0bffea01df10caa7168c48c8c5dSergey Matveev leak_report.PrintSummary(); 3096c3634b1d5eeb0bffea01df10caa7168c48c8c5dSergey Matveev Printf("\n"); 310969b529914f5bc17e4810076dccbaadf563d584cSergey Matveev *result = kLeaksFound; 311ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 312ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 313ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevvoid DoLeakCheck() { 3145e719a705666988781b9735d62cafc808ade60e2Sergey Matveev static bool already_done; 315969b529914f5bc17e4810076dccbaadf563d584cSergey Matveev LeakCheckResult result = kFatalError; 3165e719a705666988781b9735d62cafc808ade60e2Sergey Matveev LockThreadRegistry(); 3175e719a705666988781b9735d62cafc808ade60e2Sergey Matveev LockAllocator(); 3185e719a705666988781b9735d62cafc808ade60e2Sergey Matveev CHECK(!already_done); 3195e719a705666988781b9735d62cafc808ade60e2Sergey Matveev already_done = true; 3205e719a705666988781b9735d62cafc808ade60e2Sergey Matveev StopTheWorld(DoLeakCheckCallback, &result); 3215e719a705666988781b9735d62cafc808ade60e2Sergey Matveev UnlockAllocator(); 3225e719a705666988781b9735d62cafc808ade60e2Sergey Matveev UnlockThreadRegistry(); 323969b529914f5bc17e4810076dccbaadf563d584cSergey Matveev if (result == kFatalError) { 324969b529914f5bc17e4810076dccbaadf563d584cSergey Matveev Report("LeakSanitizer has encountered a fatal error.\n"); 325969b529914f5bc17e4810076dccbaadf563d584cSergey Matveev Die(); 326969b529914f5bc17e4810076dccbaadf563d584cSergey Matveev } else if (result == kLeaksFound) { 327969b529914f5bc17e4810076dccbaadf563d584cSergey Matveev if (flags()->exitcode) 328969b529914f5bc17e4810076dccbaadf563d584cSergey Matveev internal__exit(flags()->exitcode); 329969b529914f5bc17e4810076dccbaadf563d584cSergey Matveev } 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()) 3698e66cf5e2b56214996185fce37cd704898d8bc9bSergey Matveev Printf("The %llu largest leak(s):\n", max_leaks); 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++) { 3738e66cf5e2b56214996185fce37cd704898d8bc9bSergey Matveev Printf("%s leak of %llu byte(s) in %llu object(s) allocated from:\n", 374ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev leaks_[i].is_directly_leaked ? "Direct" : "Indirect", 3758e66cf5e2b56214996185fce37cd704898d8bc9bSergey Matveev leaks_[i].total_size, leaks_[i].hit_count); 376ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev PrintStackTraceById(leaks_[i].stack_trace_id); 3776c3634b1d5eeb0bffea01df10caa7168c48c8c5dSergey Matveev Printf("\n"); 378ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 379ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (max_leaks < leaks_.size()) { 380ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev uptr remaining = leaks_.size() - max_leaks; 3818e66cf5e2b56214996185fce37cd704898d8bc9bSergey Matveev Printf("Omitting %llu more leak(s).\n", remaining); 382ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 383ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 3840bc81775b75f2c8c6c8c0e1af4008771d5b882abSergey Matveev 3856c3634b1d5eeb0bffea01df10caa7168c48c8c5dSergey Matveevvoid LeakReport::PrintSummary() { 3866c3634b1d5eeb0bffea01df10caa7168c48c8c5dSergey Matveev CHECK(leaks_.size() <= kMaxLeaksConsidered); 3878e66cf5e2b56214996185fce37cd704898d8bc9bSergey Matveev uptr bytes = 0, allocations = 0; 3886c3634b1d5eeb0bffea01df10caa7168c48c8c5dSergey Matveev for (uptr i = 0; i < leaks_.size(); i++) { 3898e66cf5e2b56214996185fce37cd704898d8bc9bSergey Matveev bytes += leaks_[i].total_size; 3908e66cf5e2b56214996185fce37cd704898d8bc9bSergey Matveev allocations += leaks_[i].hit_count; 3916c3634b1d5eeb0bffea01df10caa7168c48c8c5dSergey Matveev } 3928e66cf5e2b56214996185fce37cd704898d8bc9bSergey Matveev Printf("SUMMARY: LeakSanitizer: %llu byte(s) leaked in %llu allocation(s).\n", 3938e66cf5e2b56214996185fce37cd704898d8bc9bSergey Matveev bytes, allocations); 3946c3634b1d5eeb0bffea01df10caa7168c48c8c5dSergey Matveev} 3955e719a705666988781b9735d62cafc808ade60e2Sergey Matveev 396ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} // namespace __lsan 3970bc81775b75f2c8c6c8c0e1af4008771d5b882abSergey Matveev#endif // CAN_SANITIZE_LEAKS 398