lsan_common.cc revision cd571e07fd1179383188c70338fa0dc1c452cb19
14e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)//=-- lsan_common.cc ------------------------------------------------------===// 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The LLVM Compiler Infrastructure 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 54e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// This file is distributed under the University of Illinois Open Source 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// License. See LICENSE.TXT for details. 7116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// 8116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch//===----------------------------------------------------------------------===// 9116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// 10116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// This file is a part of LeakSanitizer. 11116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Implementation of common leak checking functionality. 12116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//===----------------------------------------------------------------------===// 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "lsan_common.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sanitizer_common/sanitizer_common.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sanitizer_common/sanitizer_flags.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sanitizer_common/sanitizer_stackdepot.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sanitizer_common/sanitizer_stacktrace.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sanitizer_common/sanitizer_stoptheworld.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if CAN_SANITIZE_LEAKS 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace __lsan { 25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// This mutex is used to prevent races between DoLeakCheck and SuppressObject. 274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)BlockingMutex global_mutex(LINKER_INITIALIZED); 284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)Flags lsan_flags; 304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)static void InitializeFlags() { 324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) Flags *f = flags(); 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Default values. 34f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) f->report_blocks = false; 35116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch f->resolution = 0; 36f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) f->max_leaks = 0; 37116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch f->exitcode = 23; 38116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch f->use_registers = true; 39116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch f->use_globals = true; 40116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch f->use_stacks = true; 41116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch f->use_tls = true; 42116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch f->use_unaligned = false; 43116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch f->verbosity = 0; 44116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch f->log_pointers = false; 45f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) f->log_threads = false; 46f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 47f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const char *options = GetEnv("LSAN_OPTIONS"); 48f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (options) { 49f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ParseFlag(options, &f->use_registers, "use_registers"); 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ParseFlag(options, &f->use_globals, "use_globals"); 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ParseFlag(options, &f->use_stacks, "use_stacks"); 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ParseFlag(options, &f->use_tls, "use_tls"); 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ParseFlag(options, &f->use_unaligned, "use_unaligned"); 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ParseFlag(options, &f->report_blocks, "report_blocks"); 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ParseFlag(options, &f->resolution, "resolution"); 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_GE(&f->resolution, 0); 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ParseFlag(options, &f->max_leaks, "max_leaks"); 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_GE(&f->max_leaks, 0); 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ParseFlag(options, &f->verbosity, "verbosity"); 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ParseFlag(options, &f->log_pointers, "log_pointers"); 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ParseFlag(options, &f->log_threads, "log_threads"); 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ParseFlag(options, &f->exitcode, "exitcode"); 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InitCommonLsan() { 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InitializeFlags(); 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InitializePlatformSpecificModules(); 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static inline bool CanBeAHeapPointer(uptr p) { 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Since our heap is located in mmap-ed memory, we can assume a sensible lower 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // boundary on heap addresses. 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const uptr kMinAddress = 4 * 4096; 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (p < kMinAddress) return false; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef __x86_64__ 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Accept only canonical form user-space addresses. 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ((p >> 47) == 0); 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Scan the memory range, looking for byte patterns that point into allocator 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// chunks. Mark those chunks with tag and add them to the frontier. 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// There are two usage modes for this function: finding reachable or suppressed 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// chunks (tag = kReachable or kSuppressed) and finding indirectly leaked chunks 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (tag = kIndirectlyLeaked). In the second case, there's no flood fill, 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// so frontier = 0. 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ScanRangeForPointers(uptr begin, uptr end, InternalVector<uptr> *frontier, 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *region_type, ChunkTag tag) { 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const uptr alignment = flags()->pointer_alignment(); 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (flags()->log_pointers) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Report("Scanning %s range %p-%p.\n", region_type, begin, end); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uptr pp = begin; 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pp % alignment) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pp = pp + alignment - pp % alignment; 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (; pp + sizeof(uptr) <= end; pp += alignment) { 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void *p = *reinterpret_cast<void**>(pp); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!CanBeAHeapPointer(reinterpret_cast<uptr>(p))) continue; 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void *chunk = PointsIntoChunk(p); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!chunk) continue; 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LsanMetadata m(chunk); 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Reachable beats suppressed beats leaked. 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (m.tag() == kReachable) continue; 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (m.tag() == kSuppressed && tag != kReachable) continue; 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) m.set_tag(tag); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (flags()->log_pointers) 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Report("%p: found %p pointing into chunk %p-%p of size %llu.\n", pp, p, 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) chunk, reinterpret_cast<uptr>(chunk) + m.requested_size(), 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) m.requested_size()); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (frontier) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frontier->push_back(reinterpret_cast<uptr>(chunk)); 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Scan thread data (stacks and TLS) for heap pointers. 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void ProcessThreads(SuspendedThreadsList const &suspended_threads, 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InternalVector<uptr> *frontier) { 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InternalScopedBuffer<uptr> registers(SuspendedThreadsList::RegisterCount()); 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uptr registers_begin = reinterpret_cast<uptr>(registers.data()); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uptr registers_end = registers_begin + registers.size(); 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (uptr i = 0; i < suspended_threads.thread_count(); i++) { 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uptr os_id = static_cast<uptr>(suspended_threads.GetThreadID(i)); 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (flags()->log_threads) Report("Processing thread %d.\n", os_id); 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uptr stack_begin, stack_end, tls_begin, tls_end, cache_begin, cache_end; 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool thread_found = GetThreadRangesLocked(os_id, &stack_begin, &stack_end, 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &tls_begin, &tls_end, 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &cache_begin, &cache_end); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!thread_found) { 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If a thread can't be found in the thread registry, it's probably in the 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // process of destruction. Log this event and move on. 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (flags()->log_threads) 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Report("Thread %d not found in registry.\n", os_id); 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uptr sp; 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool have_registers = 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (suspended_threads.GetRegistersAndSP(i, registers.data(), &sp) == 0); 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!have_registers) { 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Report("Unable to get registers from thread %d.\n"); 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If unable to get SP, consider the entire stack to be reachable. 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sp = stack_begin; 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (flags()->use_registers && have_registers) 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScanRangeForPointers(registers_begin, registers_end, frontier, 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "REGISTERS", kReachable); 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (flags()->use_stacks) { 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (flags()->log_threads) 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Report("Stack at %p-%p, SP = %p.\n", stack_begin, stack_end, sp); 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (sp < stack_begin || sp >= stack_end) { 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // SP is outside the recorded stack range (e.g. the thread is running a 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // signal handler on alternate stack). Again, consider the entire stack 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // range to be reachable. 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (flags()->log_threads) 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Report("WARNING: stack_pointer not in stack_range.\n"); 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Shrink the stack range to ignore out-of-scope values. 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stack_begin = sp; 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScanRangeForPointers(stack_begin, stack_end, frontier, "STACK", 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kReachable); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (flags()->use_tls) { 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (flags()->log_threads) Report("TLS at %p-%p.\n", tls_begin, tls_end); 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (cache_begin == cache_end) { 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScanRangeForPointers(tls_begin, tls_end, frontier, "TLS", kReachable); 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Because LSan should not be loaded with dlopen(), we can assume 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // that allocator cache will be part of static TLS image. 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_LE(tls_begin, cache_begin); 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_GE(tls_end, cache_end); 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tls_begin < cache_begin) 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScanRangeForPointers(tls_begin, cache_begin, frontier, "TLS", 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kReachable); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tls_end > cache_end) 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScanRangeForPointers(cache_end, tls_end, frontier, "TLS", kReachable); 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void FloodFillTag(InternalVector<uptr> *frontier, ChunkTag tag) { 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (frontier->size()) { 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uptr next_chunk = frontier->back(); 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frontier->pop_back(); 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LsanMetadata m(reinterpret_cast<void *>(next_chunk)); 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScanRangeForPointers(next_chunk, next_chunk + m.requested_size(), frontier, 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "HEAP", tag); 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Mark leaked chunks which are reachable from other leaked chunks. 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MarkIndirectlyLeakedCb::operator()(void *p) const { 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p = GetUserBegin(p); 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LsanMetadata m(p); 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (m.allocated() && m.tag() != kReachable) { 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScanRangeForPointers(reinterpret_cast<uptr>(p), 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<uptr>(p) + m.requested_size(), 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* frontier */ 0, "HEAP", kIndirectlyLeaked); 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CollectSuppressedCb::operator()(void *p) const { 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p = GetUserBegin(p); 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LsanMetadata m(p); 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (m.allocated() && m.tag() == kSuppressed) 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frontier_->push_back(reinterpret_cast<uptr>(p)); 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Set the appropriate tag on each chunk. 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads) { 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Holds the flood fill frontier. 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InternalVector<uptr> frontier(GetPageSizeCached()); 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (flags()->use_globals) 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProcessGlobalRegions(&frontier); 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProcessThreads(suspended_threads, &frontier); 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FloodFillTag(&frontier, kReachable); 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The check here is relatively expensive, so we do this in a separate flood 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // fill. That way we can skip the check for chunks that are reachable 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // otherwise. 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProcessPlatformSpecificAllocations(&frontier); 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FloodFillTag(&frontier, kReachable); 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (flags()->log_pointers) 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Report("Scanning suppressed blocks.\n"); 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_EQ(0, frontier.size()); 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ForEachChunk(CollectSuppressedCb(&frontier)); 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FloodFillTag(&frontier, kSuppressed); 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Iterate over leaked chunks and mark those that are reachable from other 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // leaked chunks. 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (flags()->log_pointers) 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Report("Scanning leaked blocks.\n"); 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ForEachChunk(MarkIndirectlyLeakedCb()); 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void PrintStackTraceById(u32 stack_trace_id) { 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(stack_trace_id); 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uptr size = 0; 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const uptr *trace = StackDepotGet(stack_trace_id, &size); 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StackTrace::PrintStack(trace, size, common_flags()->symbolize, 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) common_flags()->strip_path_prefix, 0); 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CollectLeaksCb::operator()(void *p) const { 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p = GetUserBegin(p); 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LsanMetadata m(p); 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!m.allocated()) return; 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (m.tag() == kDirectlyLeaked || m.tag() == kIndirectlyLeaked) { 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uptr resolution = flags()->resolution; 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (resolution > 0) { 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uptr size = 0; 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const uptr *trace = StackDepotGet(m.stack_trace_id(), &size); 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size = Min(size, resolution); 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) leak_report_->Add(StackDepotPut(trace, size), m.requested_size(), 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) m.tag()); 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) leak_report_->Add(m.stack_trace_id(), m.requested_size(), m.tag()); 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void CollectLeaks(LeakReport *leak_report) { 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ForEachChunk(CollectLeaksCb(leak_report)); 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PrintLeakedCb::operator()(void *p) const { 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p = GetUserBegin(p); 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LsanMetadata m(p); 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!m.allocated()) return; 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (m.tag() == kDirectlyLeaked || m.tag() == kIndirectlyLeaked) { 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Printf("%s leaked %llu byte block at %p\n", 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) m.tag() == kDirectlyLeaked ? "Directly" : "Indirectly", 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) m.requested_size(), p); 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void PrintLeaked() { 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Printf("Reporting individual blocks:\n"); 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Printf("============================\n"); 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ForEachChunk(PrintLeakedCb()); 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Printf("\n"); 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum LeakCheckResult { 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kFatalError, 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kLeaksFound, 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kNoLeaks 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void DoLeakCheckCallback(const SuspendedThreadsList &suspended_threads, 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void *arg) { 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LeakCheckResult *result = reinterpret_cast<LeakCheckResult *>(arg); 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_EQ(*result, kFatalError); 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ClassifyAllChunks(suspended_threads); 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LeakReport leak_report; 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CollectLeaks(&leak_report); 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (leak_report.IsEmpty()) { 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *result = kNoLeaks; 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Printf("\n"); 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Printf("=================================================================\n"); 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Report("ERROR: LeakSanitizer: detected memory leaks\n"); 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) leak_report.PrintLargest(flags()->max_leaks); 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (flags()->report_blocks) 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PrintLeaked(); 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) leak_report.PrintSummary(); 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Printf("\n"); 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *result = kLeaksFound; 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DoLeakCheck() { 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BlockingMutexLock l(&global_mutex); 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static bool already_done; 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(!already_done); 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) already_done = true; 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LeakCheckResult result = kFatalError; 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LockThreadRegistry(); 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LockAllocator(); 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StopTheWorld(DoLeakCheckCallback, &result); 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UnlockAllocator(); 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UnlockThreadRegistry(); 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result == kFatalError) { 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Report("LeakSanitizer has encountered a fatal error.\n"); 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Die(); 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (result == kLeaksFound) { 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (flags()->exitcode) 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) internal__exit(flags()->exitcode); 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)///// LeakReport implementation. ///// 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A hard limit on the number of distinct leaks, to avoid quadratic complexity 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in LeakReport::Add(). We don't expect to ever see this many leaks in 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// real-world applications. 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// FIXME: Get rid of this limit by changing the implementation of LeakReport to 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// use a hash table. 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const uptr kMaxLeaksConsidered = 1000; 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LeakReport::Add(u32 stack_trace_id, uptr leaked_size, ChunkTag tag) { 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(tag == kDirectlyLeaked || tag == kIndirectlyLeaked); 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_directly_leaked = (tag == kDirectlyLeaked); 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (uptr i = 0; i < leaks_.size(); i++) 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (leaks_[i].stack_trace_id == stack_trace_id && 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) leaks_[i].is_directly_leaked == is_directly_leaked) { 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) leaks_[i].hit_count++; 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) leaks_[i].total_size += leaked_size; 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (leaks_.size() == kMaxLeaksConsidered) return; 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Leak leak = { /* hit_count */ 1, leaked_size, stack_trace_id, 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_directly_leaked }; 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) leaks_.push_back(leak); 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool IsLarger(const Leak &leak1, const Leak &leak2) { 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return leak1.total_size > leak2.total_size; 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LeakReport::PrintLargest(uptr max_leaks) { 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(leaks_.size() <= kMaxLeaksConsidered); 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Printf("\n"); 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (leaks_.size() == kMaxLeaksConsidered) 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Printf("Too many leaks! Only the first %llu leaks encountered will be " 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "reported.\n", 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kMaxLeaksConsidered); 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (max_leaks > 0 && max_leaks < leaks_.size()) 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Printf("The %llu largest leak(s):\n", max_leaks); 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InternalSort(&leaks_, leaks_.size(), IsLarger); 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) max_leaks = max_leaks > 0 ? Min(max_leaks, leaks_.size()) : leaks_.size(); 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (uptr i = 0; i < max_leaks; i++) { 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Printf("%s leak of %llu byte(s) in %llu object(s) allocated from:\n", 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) leaks_[i].is_directly_leaked ? "Direct" : "Indirect", 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) leaks_[i].total_size, leaks_[i].hit_count); 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PrintStackTraceById(leaks_[i].stack_trace_id); 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Printf("\n"); 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (max_leaks < leaks_.size()) { 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uptr remaining = leaks_.size() - max_leaks; 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Printf("Omitting %llu more leak(s).\n", remaining); 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LeakReport::PrintSummary() { 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(leaks_.size() <= kMaxLeaksConsidered); 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uptr bytes = 0, allocations = 0; 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (uptr i = 0; i < leaks_.size(); i++) { 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bytes += leaks_[i].total_size; 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) allocations += leaks_[i].hit_count; 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Printf("SUMMARY: LeakSanitizer: %llu byte(s) leaked in %llu allocation(s).\n", 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bytes, allocations); 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace __lsan 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using namespace __lsan; // NOLINT 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" { 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void __lsan_ignore_object(const void *p) { 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Cannot use PointsIntoChunk or LsanMetadata here, since the allocator is not 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // locked. 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BlockingMutexLock l(&global_mutex); 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IgnoreObjectResult res = IgnoreObjectLocked(p); 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (res == kIgnoreObjectInvalid && flags()->verbosity >= 1) 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Report("__lsan_ignore_object(): no heap object found at %p", p); 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (res == kIgnoreObjectAlreadyIgnored && flags()->verbosity >= 1) 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Report("__lsan_ignore_object(): " 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "heap object at %p is already being ignored\n", p); 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (res == kIgnoreObjectSuccess && flags()->verbosity >= 2) 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Report("__lsan_ignore_object(): ignoring heap object at %p\n", p); 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // extern "C" 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // CAN_SANITIZE_LEAKS 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)