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" 19b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev#include "sanitizer_common/sanitizer_placement_new.h" 202d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#include "sanitizer_common/sanitizer_procmaps.h" 21ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev#include "sanitizer_common/sanitizer_stackdepot.h" 22ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev#include "sanitizer_common/sanitizer_stacktrace.h" 23ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev#include "sanitizer_common/sanitizer_stoptheworld.h" 24b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev#include "sanitizer_common/sanitizer_suppressions.h" 25650c7d44b659ddfb4af471dc2ad79a727b7de939Sergey Matveev#include "sanitizer_common/sanitizer_report_decorator.h" 26ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 27ca74cff8d0f3c003a3c379bc88cc1771d8bbe1beSergey Matveev#if CAN_SANITIZE_LEAKS 2821e024eb4f1aa3c42bb9dbd1d93a4299807f9555Sergey Matveevnamespace __lsan { 290bc81775b75f2c8c6c8c0e1af4008771d5b882abSergey Matveev 302d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines// This mutex is used to prevent races between DoLeakCheck and IgnoreObject, and 312d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines// also to protect the global list of root regions. 32cd571e07fd1179383188c70338fa0dc1c452cb19Sergey MatveevBlockingMutex global_mutex(LINKER_INITIALIZED); 33cd571e07fd1179383188c70338fa0dc1c452cb19Sergey Matveev 34200afbd8ba4904241c1ebcef4fa79d739ca01f73Sergey MatveevTHREADLOCAL int disable_counter; 3521e024eb4f1aa3c42bb9dbd1d93a4299807f9555Sergey Matveevbool DisabledInThisThread() { return disable_counter > 0; } 36200afbd8ba4904241c1ebcef4fa79d739ca01f73Sergey Matveev 37ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey MatveevFlags lsan_flags; 38ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 39ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevstatic void InitializeFlags() { 40ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev Flags *f = flags(); 41ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // Default values. 42b3b46dad13a2111a51fb1a67f36c8b633410e9b7Sergey Matveev f->report_objects = false; 43ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev f->resolution = 0; 44ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev f->max_leaks = 0; 45969b529914f5bc17e4810076dccbaadf563d584cSergey Matveev f->exitcode = 23; 462d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines f->print_suppressions = true; 47b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev f->suppressions=""; 48ebe3a3608be122e799e264931f9cecf4cbc84eddSergey Matveev f->use_registers = true; 49ebe3a3608be122e799e264931f9cecf4cbc84eddSergey Matveev f->use_globals = true; 50ebe3a3608be122e799e264931f9cecf4cbc84eddSergey Matveev f->use_stacks = true; 51ebe3a3608be122e799e264931f9cecf4cbc84eddSergey Matveev f->use_tls = true; 522d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines f->use_root_regions = true; 53ebe3a3608be122e799e264931f9cecf4cbc84eddSergey Matveev f->use_unaligned = false; 542d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines f->use_poisoned = false; 55ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev f->log_pointers = false; 56ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev f->log_threads = false; 57ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 58ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev const char *options = GetEnv("LSAN_OPTIONS"); 59ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (options) { 602d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines ParseFlag(options, &f->use_registers, "use_registers", ""); 612d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines ParseFlag(options, &f->use_globals, "use_globals", ""); 622d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines ParseFlag(options, &f->use_stacks, "use_stacks", ""); 632d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines ParseFlag(options, &f->use_tls, "use_tls", ""); 642d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines ParseFlag(options, &f->use_root_regions, "use_root_regions", ""); 652d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines ParseFlag(options, &f->use_unaligned, "use_unaligned", ""); 662d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines ParseFlag(options, &f->use_poisoned, "use_poisoned", ""); 672d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines ParseFlag(options, &f->report_objects, "report_objects", ""); 682d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines ParseFlag(options, &f->resolution, "resolution", ""); 69ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev CHECK_GE(&f->resolution, 0); 702d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines ParseFlag(options, &f->max_leaks, "max_leaks", ""); 71ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev CHECK_GE(&f->max_leaks, 0); 722d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines ParseFlag(options, &f->log_pointers, "log_pointers", ""); 732d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines ParseFlag(options, &f->log_threads, "log_threads", ""); 742d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines ParseFlag(options, &f->exitcode, "exitcode", ""); 752d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines ParseFlag(options, &f->print_suppressions, "print_suppressions", ""); 762d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines ParseFlag(options, &f->suppressions, "suppressions", ""); 77ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 78ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 79ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 802d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#define LOG_POINTERS(...) \ 812d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines do { \ 822d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (flags()->log_pointers) Report(__VA_ARGS__); \ 832d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines } while (0); 842d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines 852d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#define LOG_THREADS(...) \ 862d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines do { \ 872d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (flags()->log_threads) Report(__VA_ARGS__); \ 882d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines } while (0); 892d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines 90b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey MatveevSuppressionContext *suppression_ctx; 91b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev 92b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveevvoid InitializeSuppressions() { 93b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev CHECK(!suppression_ctx); 942d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines ALIGNED(64) static char placeholder[sizeof(SuppressionContext)]; 952d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines suppression_ctx = new(placeholder) SuppressionContext; 96b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev char *suppressions_from_file; 97b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev uptr buffer_size; 98b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev if (ReadFileToBuffer(flags()->suppressions, &suppressions_from_file, 99b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev &buffer_size, 1 << 26 /* max_len */)) 100b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev suppression_ctx->Parse(suppressions_from_file); 101b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev if (flags()->suppressions[0] && !buffer_size) { 102b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev Printf("LeakSanitizer: failed to read suppressions file '%s'\n", 103b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev flags()->suppressions); 104b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev Die(); 105b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev } 106b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev if (&__lsan_default_suppressions) 107b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev suppression_ctx->Parse(__lsan_default_suppressions()); 108b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev} 109b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev 1102d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesstruct RootRegion { 1112d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines const void *begin; 1122d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines uptr size; 1132d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}; 1142d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines 1152d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen HinesInternalMmapVector<RootRegion> *root_regions; 1162d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines 1172d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid InitializeRootRegions() { 1182d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines CHECK(!root_regions); 1192d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines ALIGNED(64) static char placeholder[sizeof(InternalMmapVector<RootRegion>)]; 1202d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines root_regions = new(placeholder) InternalMmapVector<RootRegion>(1); 1212d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines} 1222d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines 123ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevvoid InitCommonLsan() { 124ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev InitializeFlags(); 1252d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines InitializeRootRegions(); 126137a9b84c25f1ad7d68a14f138cf270a03a738cbSergey Matveev if (common_flags()->detect_leaks) { 127137a9b84c25f1ad7d68a14f138cf270a03a738cbSergey Matveev // Initialization which can fail or print warnings should only be done if 128137a9b84c25f1ad7d68a14f138cf270a03a738cbSergey Matveev // LSan is actually enabled. 129137a9b84c25f1ad7d68a14f138cf270a03a738cbSergey Matveev InitializeSuppressions(); 130137a9b84c25f1ad7d68a14f138cf270a03a738cbSergey Matveev InitializePlatformSpecificModules(); 131137a9b84c25f1ad7d68a14f138cf270a03a738cbSergey Matveev } 132ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 133ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 1345d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hinesclass Decorator: public __sanitizer::SanitizerCommonDecorator { 135650c7d44b659ddfb4af471dc2ad79a727b7de939Sergey Matveev public: 1365d71de26cedae3dafc17449fe0182045c0bd20e8Stephen Hines Decorator() : SanitizerCommonDecorator() { } 137650c7d44b659ddfb4af471dc2ad79a727b7de939Sergey Matveev const char *Error() { return Red(); } 138650c7d44b659ddfb4af471dc2ad79a727b7de939Sergey Matveev const char *Leak() { return Blue(); } 139650c7d44b659ddfb4af471dc2ad79a727b7de939Sergey Matveev const char *End() { return Default(); } 140650c7d44b659ddfb4af471dc2ad79a727b7de939Sergey Matveev}; 141650c7d44b659ddfb4af471dc2ad79a727b7de939Sergey Matveev 142ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevstatic inline bool CanBeAHeapPointer(uptr p) { 143ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // Since our heap is located in mmap-ed memory, we can assume a sensible lower 144b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev // bound on heap addresses. 145ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev const uptr kMinAddress = 4 * 4096; 146ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (p < kMinAddress) return false; 147ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev#ifdef __x86_64__ 148ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // Accept only canonical form user-space addresses. 149ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev return ((p >> 47) == 0); 150ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev#else 151ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev return true; 152ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev#endif 153ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 154ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 155ac78d0087281e9b40bb043f827fbde8c05c6505aSergey Matveev// Scans the memory range, looking for byte patterns that point into allocator 156ac78d0087281e9b40bb043f827fbde8c05c6505aSergey Matveev// chunks. Marks those chunks with |tag| and adds them to |frontier|. 157ac78d0087281e9b40bb043f827fbde8c05c6505aSergey Matveev// There are two usage modes for this function: finding reachable or ignored 158ac78d0087281e9b40bb043f827fbde8c05c6505aSergey Matveev// chunks (|tag| = kReachable or kIgnored) and finding indirectly leaked chunks 159ac78d0087281e9b40bb043f827fbde8c05c6505aSergey Matveev// (|tag| = kIndirectlyLeaked). In the second case, there's no flood fill, 160ac78d0087281e9b40bb043f827fbde8c05c6505aSergey Matveev// so |frontier| = 0. 161a64d4359902f1f64992aedfe10d8882ae7c66f40Alexey Samsonovvoid ScanRangeForPointers(uptr begin, uptr end, 162dbeb48d34bb6447c33a0ef99aaf9ba36f7f4b852Alexey Samsonov Frontier *frontier, 163ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev const char *region_type, ChunkTag tag) { 164ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev const uptr alignment = flags()->pointer_alignment(); 1652d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines LOG_POINTERS("Scanning %s range %p-%p.\n", region_type, begin, end); 166ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev uptr pp = begin; 167ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (pp % alignment) 168ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev pp = pp + alignment - pp % alignment; 169ac78d0087281e9b40bb043f827fbde8c05c6505aSergey Matveev for (; pp + sizeof(void *) <= end; pp += alignment) { // NOLINT 170f93fa97b9fb49c6aaeeadf94fc54c76374b580bdSergey Matveev void *p = *reinterpret_cast<void **>(pp); 171ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (!CanBeAHeapPointer(reinterpret_cast<uptr>(p))) continue; 172ac78d0087281e9b40bb043f827fbde8c05c6505aSergey Matveev uptr chunk = PointsIntoChunk(p); 173ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (!chunk) continue; 174e852e41d345c4be4ca28962cbc6c6d59717759c7Sergey Matveev // Pointers to self don't count. This matters when tag == kIndirectlyLeaked. 175e852e41d345c4be4ca28962cbc6c6d59717759c7Sergey Matveev if (chunk == begin) continue; 176ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev LsanMetadata m(chunk); 177200afbd8ba4904241c1ebcef4fa79d739ca01f73Sergey Matveev // Reachable beats ignored beats leaked. 178ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (m.tag() == kReachable) continue; 179b3b46dad13a2111a51fb1a67f36c8b633410e9b7Sergey Matveev if (m.tag() == kIgnored && tag != kReachable) continue; 1802d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines 1812d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines // Do this check relatively late so we can log only the interesting cases. 1822d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (!flags()->use_poisoned && WordIsPoisoned(pp)) { 1832d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines LOG_POINTERS( 1842d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines "%p is poisoned: ignoring %p pointing into chunk %p-%p of size " 1852d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines "%zu.\n", 1862d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines pp, p, chunk, chunk + m.requested_size(), m.requested_size()); 1872d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines continue; 1882d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines } 1892d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines 190ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev m.set_tag(tag); 1912d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines LOG_POINTERS("%p: found %p pointing into chunk %p-%p of size %zu.\n", pp, p, 1922d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines chunk, chunk + m.requested_size(), m.requested_size()); 193ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (frontier) 194ac78d0087281e9b40bb043f827fbde8c05c6505aSergey Matveev frontier->push_back(chunk); 195ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 196ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 197ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 198c519335c2d6d32acaac32c0595f08a05081567e7Sergey Matveevvoid ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg) { 199c519335c2d6d32acaac32c0595f08a05081567e7Sergey Matveev Frontier *frontier = reinterpret_cast<Frontier *>(arg); 200c519335c2d6d32acaac32c0595f08a05081567e7Sergey Matveev ScanRangeForPointers(begin, end, frontier, "FAKE STACK", kReachable); 201c519335c2d6d32acaac32c0595f08a05081567e7Sergey Matveev} 202c519335c2d6d32acaac32c0595f08a05081567e7Sergey Matveev 203ac78d0087281e9b40bb043f827fbde8c05c6505aSergey Matveev// Scans thread data (stacks and TLS) for heap pointers. 204ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevstatic void ProcessThreads(SuspendedThreadsList const &suspended_threads, 205dbeb48d34bb6447c33a0ef99aaf9ba36f7f4b852Alexey Samsonov Frontier *frontier) { 206ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev InternalScopedBuffer<uptr> registers(SuspendedThreadsList::RegisterCount()); 207ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev uptr registers_begin = reinterpret_cast<uptr>(registers.data()); 208ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev uptr registers_end = registers_begin + registers.size(); 209ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev for (uptr i = 0; i < suspended_threads.thread_count(); i++) { 210ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev uptr os_id = static_cast<uptr>(suspended_threads.GetThreadID(i)); 2112d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines LOG_THREADS("Processing thread %d.\n", os_id); 212ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev uptr stack_begin, stack_end, tls_begin, tls_end, cache_begin, cache_end; 213ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev bool thread_found = GetThreadRangesLocked(os_id, &stack_begin, &stack_end, 214ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev &tls_begin, &tls_end, 215ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev &cache_begin, &cache_end); 216ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (!thread_found) { 217ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // If a thread can't be found in the thread registry, it's probably in the 218ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // process of destruction. Log this event and move on. 2192d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines LOG_THREADS("Thread %d not found in registry.\n", os_id); 220ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev continue; 221ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 222ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev uptr sp; 223ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev bool have_registers = 224ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev (suspended_threads.GetRegistersAndSP(i, registers.data(), &sp) == 0); 225ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (!have_registers) { 226ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev Report("Unable to get registers from thread %d.\n"); 227ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // If unable to get SP, consider the entire stack to be reachable. 228ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev sp = stack_begin; 229ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 230ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 231ebe3a3608be122e799e264931f9cecf4cbc84eddSergey Matveev if (flags()->use_registers && have_registers) 232ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ScanRangeForPointers(registers_begin, registers_end, frontier, 233ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev "REGISTERS", kReachable); 234ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 235ebe3a3608be122e799e264931f9cecf4cbc84eddSergey Matveev if (flags()->use_stacks) { 2362d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines LOG_THREADS("Stack at %p-%p (SP = %p).\n", stack_begin, stack_end, sp); 237ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (sp < stack_begin || sp >= stack_end) { 238ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // SP is outside the recorded stack range (e.g. the thread is running a 239ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // signal handler on alternate stack). Again, consider the entire stack 240ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // range to be reachable. 2412d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines LOG_THREADS("WARNING: stack pointer not in stack range.\n"); 242ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } else { 243ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // Shrink the stack range to ignore out-of-scope values. 244ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev stack_begin = sp; 245ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 246ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ScanRangeForPointers(stack_begin, stack_end, frontier, "STACK", 247ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev kReachable); 248c519335c2d6d32acaac32c0595f08a05081567e7Sergey Matveev ForEachExtraStackRange(os_id, ForEachExtraStackRangeCb, frontier); 249ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 250ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 251ebe3a3608be122e799e264931f9cecf4cbc84eddSergey Matveev if (flags()->use_tls) { 2522d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines LOG_THREADS("TLS at %p-%p.\n", tls_begin, tls_end); 253f5a9ace4904e9daf3d962274cbbcb702ebc5450eSergey Matveev if (cache_begin == cache_end) { 254f5a9ace4904e9daf3d962274cbbcb702ebc5450eSergey Matveev ScanRangeForPointers(tls_begin, tls_end, frontier, "TLS", kReachable); 255f5a9ace4904e9daf3d962274cbbcb702ebc5450eSergey Matveev } else { 256f5a9ace4904e9daf3d962274cbbcb702ebc5450eSergey Matveev // Because LSan should not be loaded with dlopen(), we can assume 257f5a9ace4904e9daf3d962274cbbcb702ebc5450eSergey Matveev // that allocator cache will be part of static TLS image. 258f5a9ace4904e9daf3d962274cbbcb702ebc5450eSergey Matveev CHECK_LE(tls_begin, cache_begin); 259f5a9ace4904e9daf3d962274cbbcb702ebc5450eSergey Matveev CHECK_GE(tls_end, cache_end); 260f5a9ace4904e9daf3d962274cbbcb702ebc5450eSergey Matveev if (tls_begin < cache_begin) 261f5a9ace4904e9daf3d962274cbbcb702ebc5450eSergey Matveev ScanRangeForPointers(tls_begin, cache_begin, frontier, "TLS", 262f5a9ace4904e9daf3d962274cbbcb702ebc5450eSergey Matveev kReachable); 263f5a9ace4904e9daf3d962274cbbcb702ebc5450eSergey Matveev if (tls_end > cache_end) 264f5a9ace4904e9daf3d962274cbbcb702ebc5450eSergey Matveev ScanRangeForPointers(cache_end, tls_end, frontier, "TLS", kReachable); 265f5a9ace4904e9daf3d962274cbbcb702ebc5450eSergey Matveev } 266ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 267ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 268ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 269ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 2702d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesstatic void ProcessRootRegion(Frontier *frontier, uptr root_begin, 2712d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines uptr root_end) { 2722d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines MemoryMappingLayout proc_maps(/*cache_enabled*/true); 2732d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines uptr begin, end, prot; 2742d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines while (proc_maps.Next(&begin, &end, 2752d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines /*offset*/ 0, /*filename*/ 0, /*filename_size*/ 0, 2762d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines &prot)) { 2772d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines uptr intersection_begin = Max(root_begin, begin); 2782d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines uptr intersection_end = Min(end, root_end); 2792d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (intersection_begin >= intersection_end) continue; 2802d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines bool is_readable = prot & MemoryMappingLayout::kProtectionRead; 2812d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines LOG_POINTERS("Root region %p-%p intersects with mapped region %p-%p (%s)\n", 2822d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines root_begin, root_end, begin, end, 2832d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines is_readable ? "readable" : "unreadable"); 2842d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (is_readable) 2852d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines ScanRangeForPointers(intersection_begin, intersection_end, frontier, 2862d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines "ROOT", kReachable); 2872d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines } 2882d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines} 2892d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines 2902d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines// Scans root regions for heap pointers. 2912d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesstatic void ProcessRootRegions(Frontier *frontier) { 2922d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (!flags()->use_root_regions) return; 2932d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines CHECK(root_regions); 2942d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines for (uptr i = 0; i < root_regions->size(); i++) { 2952d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines RootRegion region = (*root_regions)[i]; 2962d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines uptr begin_addr = reinterpret_cast<uptr>(region.begin); 2972d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines ProcessRootRegion(frontier, begin_addr, begin_addr + region.size); 2982d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines } 2992d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines} 3002d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines 301dbeb48d34bb6447c33a0ef99aaf9ba36f7f4b852Alexey Samsonovstatic void FloodFillTag(Frontier *frontier, ChunkTag tag) { 302ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev while (frontier->size()) { 303ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev uptr next_chunk = frontier->back(); 304ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev frontier->pop_back(); 305ac78d0087281e9b40bb043f827fbde8c05c6505aSergey Matveev LsanMetadata m(next_chunk); 306ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ScanRangeForPointers(next_chunk, next_chunk + m.requested_size(), frontier, 3075e719a705666988781b9735d62cafc808ade60e2Sergey Matveev "HEAP", tag); 308ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 309ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 310ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 311ac78d0087281e9b40bb043f827fbde8c05c6505aSergey Matveev// ForEachChunk callback. If the chunk is marked as leaked, marks all chunks 312ac78d0087281e9b40bb043f827fbde8c05c6505aSergey Matveev// which are reachable from it as indirectly leaked. 313ac78d0087281e9b40bb043f827fbde8c05c6505aSergey Matveevstatic void MarkIndirectlyLeakedCb(uptr chunk, void *arg) { 314ac78d0087281e9b40bb043f827fbde8c05c6505aSergey Matveev chunk = GetUserBegin(chunk); 315ac78d0087281e9b40bb043f827fbde8c05c6505aSergey Matveev LsanMetadata m(chunk); 316ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (m.allocated() && m.tag() != kReachable) { 317ac78d0087281e9b40bb043f827fbde8c05c6505aSergey Matveev ScanRangeForPointers(chunk, chunk + m.requested_size(), 318ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev /* frontier */ 0, "HEAP", kIndirectlyLeaked); 319ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 320ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 321ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 322ac78d0087281e9b40bb043f827fbde8c05c6505aSergey Matveev// ForEachChunk callback. If chunk is marked as ignored, adds its address to 323ac78d0087281e9b40bb043f827fbde8c05c6505aSergey Matveev// frontier. 324ac78d0087281e9b40bb043f827fbde8c05c6505aSergey Matveevstatic void CollectIgnoredCb(uptr chunk, void *arg) { 325ac78d0087281e9b40bb043f827fbde8c05c6505aSergey Matveev CHECK(arg); 326ac78d0087281e9b40bb043f827fbde8c05c6505aSergey Matveev chunk = GetUserBegin(chunk); 327ac78d0087281e9b40bb043f827fbde8c05c6505aSergey Matveev LsanMetadata m(chunk); 328b3b46dad13a2111a51fb1a67f36c8b633410e9b7Sergey Matveev if (m.allocated() && m.tag() == kIgnored) 329ac78d0087281e9b40bb043f827fbde8c05c6505aSergey Matveev reinterpret_cast<Frontier *>(arg)->push_back(chunk); 3305e719a705666988781b9735d62cafc808ade60e2Sergey Matveev} 3315e719a705666988781b9735d62cafc808ade60e2Sergey Matveev 332ac78d0087281e9b40bb043f827fbde8c05c6505aSergey Matveev// Sets the appropriate tag on each chunk. 333ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevstatic void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads) { 334ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev // Holds the flood fill frontier. 3352d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Frontier frontier(1); 336ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 3372d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines ProcessGlobalRegions(&frontier); 338ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ProcessThreads(suspended_threads, &frontier); 3392d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines ProcessRootRegions(&frontier); 3405e719a705666988781b9735d62cafc808ade60e2Sergey Matveev FloodFillTag(&frontier, kReachable); 3415e719a705666988781b9735d62cafc808ade60e2Sergey Matveev // The check here is relatively expensive, so we do this in a separate flood 3425e719a705666988781b9735d62cafc808ade60e2Sergey Matveev // fill. That way we can skip the check for chunks that are reachable 3435e719a705666988781b9735d62cafc808ade60e2Sergey Matveev // otherwise. 3442d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines LOG_POINTERS("Processing platform-specific allocations.\n"); 345ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ProcessPlatformSpecificAllocations(&frontier); 3465e719a705666988781b9735d62cafc808ade60e2Sergey Matveev FloodFillTag(&frontier, kReachable); 347ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 3482d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines LOG_POINTERS("Scanning ignored chunks.\n"); 3495e719a705666988781b9735d62cafc808ade60e2Sergey Matveev CHECK_EQ(0, frontier.size()); 350ac78d0087281e9b40bb043f827fbde8c05c6505aSergey Matveev ForEachChunk(CollectIgnoredCb, &frontier); 351b3b46dad13a2111a51fb1a67f36c8b633410e9b7Sergey Matveev FloodFillTag(&frontier, kIgnored); 352ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 3535e719a705666988781b9735d62cafc808ade60e2Sergey Matveev // Iterate over leaked chunks and mark those that are reachable from other 3545e719a705666988781b9735d62cafc808ade60e2Sergey Matveev // leaked chunks. 3552d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines LOG_POINTERS("Scanning leaked chunks.\n"); 356ac78d0087281e9b40bb043f827fbde8c05c6505aSergey Matveev ForEachChunk(MarkIndirectlyLeakedCb, 0 /* arg */); 357ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 358ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 359ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevstatic void PrintStackTraceById(u32 stack_trace_id) { 360ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev CHECK(stack_trace_id); 361ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev uptr size = 0; 362ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev const uptr *trace = StackDepotGet(stack_trace_id, &size); 3637996a2e2a1c461743c9216f13429c04d75050230Alexey Samsonov StackTrace::PrintStack(trace, size); 364ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 365ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 3662d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines// ForEachChunk callback. Aggregates information about unreachable chunks into 3672d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines// a LeakReport. 368ac78d0087281e9b40bb043f827fbde8c05c6505aSergey Matveevstatic void CollectLeaksCb(uptr chunk, void *arg) { 369ac78d0087281e9b40bb043f827fbde8c05c6505aSergey Matveev CHECK(arg); 370ac78d0087281e9b40bb043f827fbde8c05c6505aSergey Matveev LeakReport *leak_report = reinterpret_cast<LeakReport *>(arg); 371ac78d0087281e9b40bb043f827fbde8c05c6505aSergey Matveev chunk = GetUserBegin(chunk); 372ac78d0087281e9b40bb043f827fbde8c05c6505aSergey Matveev LsanMetadata m(chunk); 373ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (!m.allocated()) return; 3745e719a705666988781b9735d62cafc808ade60e2Sergey Matveev if (m.tag() == kDirectlyLeaked || m.tag() == kIndirectlyLeaked) { 375ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev uptr resolution = flags()->resolution; 3762d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines u32 stack_trace_id = 0; 377ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (resolution > 0) { 3782946f13d6ca0cfc46d74c12e97dc40a17a7d232fAlexey Samsonov uptr size = 0; 3792946f13d6ca0cfc46d74c12e97dc40a17a7d232fAlexey Samsonov const uptr *trace = StackDepotGet(m.stack_trace_id(), &size); 380ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev size = Min(size, resolution); 3812d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines stack_trace_id = StackDepotPut(trace, size); 382ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } else { 3832d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines stack_trace_id = m.stack_trace_id(); 384ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 3852d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines leak_report->AddLeakedChunk(chunk, stack_trace_id, m.requested_size(), 3862d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines m.tag()); 387ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 388ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 389ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 390b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveevstatic void PrintMatchedSuppressions() { 391b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev InternalMmapVector<Suppression *> matched(1); 392b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev suppression_ctx->GetMatched(&matched); 393b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev if (!matched.size()) 394b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev return; 395b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev const char *line = "-----------------------------------------------------"; 396b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev Printf("%s\n", line); 397b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev Printf("Suppressions used:\n"); 398b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev Printf(" count bytes template\n"); 399b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev for (uptr i = 0; i < matched.size(); i++) 400b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev Printf("%7zu %10zu %s\n", static_cast<uptr>(matched[i]->hit_count), 401b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev matched[i]->weight, matched[i]->templ); 402b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev Printf("%s\n\n", line); 403b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev} 404b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev 405c085fe807836b566b4fce7ccdfb307bb025693c5Sergey Matveevstruct DoLeakCheckParam { 406c085fe807836b566b4fce7ccdfb307bb025693c5Sergey Matveev bool success; 407c085fe807836b566b4fce7ccdfb307bb025693c5Sergey Matveev LeakReport leak_report; 408969b529914f5bc17e4810076dccbaadf563d584cSergey Matveev}; 409969b529914f5bc17e4810076dccbaadf563d584cSergey Matveev 410ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevstatic void DoLeakCheckCallback(const SuspendedThreadsList &suspended_threads, 411ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev void *arg) { 412c085fe807836b566b4fce7ccdfb307bb025693c5Sergey Matveev DoLeakCheckParam *param = reinterpret_cast<DoLeakCheckParam *>(arg); 413c085fe807836b566b4fce7ccdfb307bb025693c5Sergey Matveev CHECK(param); 414c085fe807836b566b4fce7ccdfb307bb025693c5Sergey Matveev CHECK(!param->success); 415ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev ClassifyAllChunks(suspended_threads); 416ac78d0087281e9b40bb043f827fbde8c05c6505aSergey Matveev ForEachChunk(CollectLeaksCb, ¶m->leak_report); 417c085fe807836b566b4fce7ccdfb307bb025693c5Sergey Matveev param->success = true; 418ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 419ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 420ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveevvoid DoLeakCheck() { 421c6ac98d7fcc81768b2ef7ddc785c27e3fc1bdef6Sergey Matveev EnsureMainThreadIDIsCorrect(); 422cd571e07fd1179383188c70338fa0dc1c452cb19Sergey Matveev BlockingMutexLock l(&global_mutex); 4235e719a705666988781b9735d62cafc808ade60e2Sergey Matveev static bool already_done; 424f93fa97b9fb49c6aaeeadf94fc54c76374b580bdSergey Matveev if (already_done) return; 425cd571e07fd1179383188c70338fa0dc1c452cb19Sergey Matveev already_done = true; 4269fbfd96608070eb71e11fbfe42ec9e84016429aeAlexey Samsonov if (&__lsan_is_turned_off && __lsan_is_turned_off()) 4272d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines return; 428c085fe807836b566b4fce7ccdfb307bb025693c5Sergey Matveev 429c085fe807836b566b4fce7ccdfb307bb025693c5Sergey Matveev DoLeakCheckParam param; 430c085fe807836b566b4fce7ccdfb307bb025693c5Sergey Matveev param.success = false; 4315e719a705666988781b9735d62cafc808ade60e2Sergey Matveev LockThreadRegistry(); 4325e719a705666988781b9735d62cafc808ade60e2Sergey Matveev LockAllocator(); 433c085fe807836b566b4fce7ccdfb307bb025693c5Sergey Matveev StopTheWorld(DoLeakCheckCallback, ¶m); 4345e719a705666988781b9735d62cafc808ade60e2Sergey Matveev UnlockAllocator(); 4355e719a705666988781b9735d62cafc808ade60e2Sergey Matveev UnlockThreadRegistry(); 436c085fe807836b566b4fce7ccdfb307bb025693c5Sergey Matveev 437c085fe807836b566b4fce7ccdfb307bb025693c5Sergey Matveev if (!param.success) { 438969b529914f5bc17e4810076dccbaadf563d584cSergey Matveev Report("LeakSanitizer has encountered a fatal error.\n"); 439969b529914f5bc17e4810076dccbaadf563d584cSergey Matveev Die(); 440c085fe807836b566b4fce7ccdfb307bb025693c5Sergey Matveev } 4412d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines param.leak_report.ApplySuppressions(); 4422d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines uptr unsuppressed_count = param.leak_report.UnsuppressedLeakCount(); 4432d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (unsuppressed_count > 0) { 444650c7d44b659ddfb4af471dc2ad79a727b7de939Sergey Matveev Decorator d; 4459b4ba948f1c19adafde8e78c520ce30ac7bb1033Sergey Matveev Printf("\n" 4469b4ba948f1c19adafde8e78c520ce30ac7bb1033Sergey Matveev "=================================================================" 447c085fe807836b566b4fce7ccdfb307bb025693c5Sergey Matveev "\n"); 448650c7d44b659ddfb4af471dc2ad79a727b7de939Sergey Matveev Printf("%s", d.Error()); 449c085fe807836b566b4fce7ccdfb307bb025693c5Sergey Matveev Report("ERROR: LeakSanitizer: detected memory leaks\n"); 450650c7d44b659ddfb4af471dc2ad79a727b7de939Sergey Matveev Printf("%s", d.End()); 4512d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines param.leak_report.ReportTopLeaks(flags()->max_leaks); 4529b4ba948f1c19adafde8e78c520ce30ac7bb1033Sergey Matveev } 4532d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (flags()->print_suppressions) 454b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev PrintMatchedSuppressions(); 4552d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (unsuppressed_count > 0) { 456c085fe807836b566b4fce7ccdfb307bb025693c5Sergey Matveev param.leak_report.PrintSummary(); 4572d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (flags()->exitcode) 4582d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines internal__exit(flags()->exitcode); 459969b529914f5bc17e4810076dccbaadf563d584cSergey Matveev } 460ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 461ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 462b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveevstatic Suppression *GetSuppressionForAddr(uptr addr) { 4632d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Suppression *s; 4642d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines 4652d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines // Suppress by module name. 4662d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines const char *module_name; 4672d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines uptr module_offset; 4682d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (Symbolizer::Get()->GetModuleNameAndOffsetForPC(addr, &module_name, 4692d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines &module_offset) && 4702d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines suppression_ctx->Match(module_name, SuppressionLeak, &s)) 4712d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines return s; 4722d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines 4732d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines // Suppress by file or function name. 474b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev static const uptr kMaxAddrFrames = 16; 475b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev InternalScopedBuffer<AddressInfo> addr_frames(kMaxAddrFrames); 476b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev for (uptr i = 0; i < kMaxAddrFrames; i++) new (&addr_frames[i]) AddressInfo(); 4772d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines uptr addr_frames_num = Symbolizer::Get()->SymbolizePC( 478c1a1ed62228288155459d39194995a36aca4a8a6Peter Collingbourne addr, addr_frames.data(), kMaxAddrFrames); 479b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev for (uptr i = 0; i < addr_frames_num; i++) { 480b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev if (suppression_ctx->Match(addr_frames[i].function, SuppressionLeak, &s) || 4812d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines suppression_ctx->Match(addr_frames[i].file, SuppressionLeak, &s)) 482b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev return s; 483b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev } 484b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev return 0; 485b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev} 486b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev 487b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveevstatic Suppression *GetSuppressionForStack(u32 stack_trace_id) { 488b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev uptr size = 0; 489b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev const uptr *trace = StackDepotGet(stack_trace_id, &size); 490b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev for (uptr i = 0; i < size; i++) { 491b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev Suppression *s = 492b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev GetSuppressionForAddr(StackTrace::GetPreviousInstructionPc(trace[i])); 493b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev if (s) return s; 494b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev } 495b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev return 0; 496b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev} 497b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev 498ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev///// LeakReport implementation. ///// 499ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 500ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev// A hard limit on the number of distinct leaks, to avoid quadratic complexity 5012d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines// in LeakReport::AddLeakedChunk(). We don't expect to ever see this many leaks 5022d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines// in real-world applications. 503ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev// FIXME: Get rid of this limit by changing the implementation of LeakReport to 504ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev// use a hash table. 505bac1f7b034d9b3bb15d98db755a2bc091c8ce005Sergey Matveevconst uptr kMaxLeaksConsidered = 5000; 506ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 5072d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid LeakReport::AddLeakedChunk(uptr chunk, u32 stack_trace_id, 5082d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines uptr leaked_size, ChunkTag tag) { 509ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev CHECK(tag == kDirectlyLeaked || tag == kIndirectlyLeaked); 510ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev bool is_directly_leaked = (tag == kDirectlyLeaked); 5112d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines uptr i; 5122d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines for (i = 0; i < leaks_.size(); i++) { 513ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (leaks_[i].stack_trace_id == stack_trace_id && 514ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev leaks_[i].is_directly_leaked == is_directly_leaked) { 515ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev leaks_[i].hit_count++; 516ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev leaks_[i].total_size += leaked_size; 5172d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines break; 518ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 5192d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines } 5202d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (i == leaks_.size()) { 5212d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (leaks_.size() == kMaxLeaksConsidered) return; 5222d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Leak leak = { next_id_++, /* hit_count */ 1, leaked_size, stack_trace_id, 5232d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines is_directly_leaked, /* is_suppressed */ false }; 5242d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines leaks_.push_back(leak); 5252d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines } 5262d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (flags()->report_objects) { 5272d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines LeakedObject obj = {leaks_[i].id, chunk, leaked_size}; 5282d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines leaked_objects_.push_back(obj); 5292d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines } 530ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 531ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 532841b6f29df24642cfbaa6e6fba5632d1712569aeSergey Matveevstatic bool LeakComparator(const Leak &leak1, const Leak &leak2) { 533841b6f29df24642cfbaa6e6fba5632d1712569aeSergey Matveev if (leak1.is_directly_leaked == leak2.is_directly_leaked) 534841b6f29df24642cfbaa6e6fba5632d1712569aeSergey Matveev return leak1.total_size > leak2.total_size; 535841b6f29df24642cfbaa6e6fba5632d1712569aeSergey Matveev else 536841b6f29df24642cfbaa6e6fba5632d1712569aeSergey Matveev return leak1.is_directly_leaked; 537ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 538ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev 5392d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid LeakReport::ReportTopLeaks(uptr num_leaks_to_report) { 540ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev CHECK(leaks_.size() <= kMaxLeaksConsidered); 541ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev Printf("\n"); 542ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev if (leaks_.size() == kMaxLeaksConsidered) 543ef89d6b576bd8f5084b70e2d908cd53c37fab9f9Sergey Matveev Printf("Too many leaks! Only the first %zu leaks encountered will be " 544ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev "reported.\n", 545ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev kMaxLeaksConsidered); 546b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev 5472d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines uptr unsuppressed_count = UnsuppressedLeakCount(); 5482d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (num_leaks_to_report > 0 && num_leaks_to_report < unsuppressed_count) 5492d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Printf("The %zu top leak(s):\n", num_leaks_to_report); 550841b6f29df24642cfbaa6e6fba5632d1712569aeSergey Matveev InternalSort(&leaks_, leaks_.size(), LeakComparator); 5512d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines uptr leaks_reported = 0; 552b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev for (uptr i = 0; i < leaks_.size(); i++) { 553b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev if (leaks_[i].is_suppressed) continue; 5542d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines PrintReportForLeak(i); 5552d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines leaks_reported++; 5562d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (leaks_reported == num_leaks_to_report) break; 557ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 5582d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (leaks_reported < unsuppressed_count) { 5592d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines uptr remaining = unsuppressed_count - leaks_reported; 560ef89d6b576bd8f5084b70e2d908cd53c37fab9f9Sergey Matveev Printf("Omitting %zu more leak(s).\n", remaining); 561ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev } 562ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} 5630bc81775b75f2c8c6c8c0e1af4008771d5b882abSergey Matveev 5642d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid LeakReport::PrintReportForLeak(uptr index) { 5652d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Decorator d; 5662d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Printf("%s", d.Leak()); 5672d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Printf("%s leak of %zu byte(s) in %zu object(s) allocated from:\n", 5682d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines leaks_[index].is_directly_leaked ? "Direct" : "Indirect", 5692d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines leaks_[index].total_size, leaks_[index].hit_count); 5702d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Printf("%s", d.End()); 5712d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines 5722d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines PrintStackTraceById(leaks_[index].stack_trace_id); 5732d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines 5742d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (flags()->report_objects) { 5752d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Printf("Objects leaked above:\n"); 5762d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines PrintLeakedObjectsForLeak(index); 5772d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Printf("\n"); 5782d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines } 5792d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines} 5802d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines 5812d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid LeakReport::PrintLeakedObjectsForLeak(uptr index) { 5822d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines u32 leak_id = leaks_[index].id; 5832d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines for (uptr j = 0; j < leaked_objects_.size(); j++) { 5842d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (leaked_objects_[j].leak_id == leak_id) 5852d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Printf("%p (%zu bytes)\n", leaked_objects_[j].addr, 5862d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines leaked_objects_[j].size); 5872d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines } 5882d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines} 5892d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines 5906c3634b1d5eeb0bffea01df10caa7168c48c8c5dSergey Matveevvoid LeakReport::PrintSummary() { 5916c3634b1d5eeb0bffea01df10caa7168c48c8c5dSergey Matveev CHECK(leaks_.size() <= kMaxLeaksConsidered); 5928e66cf5e2b56214996185fce37cd704898d8bc9bSergey Matveev uptr bytes = 0, allocations = 0; 5936c3634b1d5eeb0bffea01df10caa7168c48c8c5dSergey Matveev for (uptr i = 0; i < leaks_.size(); i++) { 594b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev if (leaks_[i].is_suppressed) continue; 5958e66cf5e2b56214996185fce37cd704898d8bc9bSergey Matveev bytes += leaks_[i].total_size; 5968e66cf5e2b56214996185fce37cd704898d8bc9bSergey Matveev allocations += leaks_[i].hit_count; 5976c3634b1d5eeb0bffea01df10caa7168c48c8c5dSergey Matveev } 59899560bf109ca14b1a48e1ae1206bcc11cdb7eae4Alexey Samsonov InternalScopedBuffer<char> summary(kMaxSummaryLength); 5992fb08720b11b4c339e191b90d85477c6a2dd74dbAlexey Samsonov internal_snprintf(summary.data(), summary.size(), 6002fb08720b11b4c339e191b90d85477c6a2dd74dbAlexey Samsonov "%zu byte(s) leaked in %zu allocation(s).", bytes, 6012fb08720b11b4c339e191b90d85477c6a2dd74dbAlexey Samsonov allocations); 6022fb08720b11b4c339e191b90d85477c6a2dd74dbAlexey Samsonov ReportErrorSummary(summary.data()); 6036c3634b1d5eeb0bffea01df10caa7168c48c8c5dSergey Matveev} 604b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev 6052d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid LeakReport::ApplySuppressions() { 606b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev for (uptr i = 0; i < leaks_.size(); i++) { 607b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev Suppression *s = GetSuppressionForStack(leaks_[i].stack_trace_id); 608b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev if (s) { 609b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev s->weight += leaks_[i].total_size; 610b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev s->hit_count += leaks_[i].hit_count; 611b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev leaks_[i].is_suppressed = true; 612b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev } 613b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev } 614b33cfeb6004d3a93e6d35749c14db0190c6c2b4cSergey Matveev} 6152d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines 6162d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesuptr LeakReport::UnsuppressedLeakCount() { 6172d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines uptr result = 0; 6182d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines for (uptr i = 0; i < leaks_.size(); i++) 6192d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (!leaks_[i].is_suppressed) result++; 6202d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines return result; 6212d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines} 6222d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines 623ab0f74438abd73342a9d09e1d8b687461cf18da1Sergey Matveev} // namespace __lsan 62421e024eb4f1aa3c42bb9dbd1d93a4299807f9555Sergey Matveev#endif // CAN_SANITIZE_LEAKS 625cd571e07fd1179383188c70338fa0dc1c452cb19Sergey Matveev 626cd571e07fd1179383188c70338fa0dc1c452cb19Sergey Matveevusing namespace __lsan; // NOLINT 627cd571e07fd1179383188c70338fa0dc1c452cb19Sergey Matveev 628cd571e07fd1179383188c70338fa0dc1c452cb19Sergey Matveevextern "C" { 62946ed75f54f1c3b7863ae74aec8c2c015d572f027Sergey MatveevSANITIZER_INTERFACE_ATTRIBUTE 630cd571e07fd1179383188c70338fa0dc1c452cb19Sergey Matveevvoid __lsan_ignore_object(const void *p) { 6319b618a7ec2ec78e602d8897008c6f02cba673794Sergey Matveev#if CAN_SANITIZE_LEAKS 632137a9b84c25f1ad7d68a14f138cf270a03a738cbSergey Matveev if (!common_flags()->detect_leaks) 633137a9b84c25f1ad7d68a14f138cf270a03a738cbSergey Matveev return; 634cd571e07fd1179383188c70338fa0dc1c452cb19Sergey Matveev // Cannot use PointsIntoChunk or LsanMetadata here, since the allocator is not 635cd571e07fd1179383188c70338fa0dc1c452cb19Sergey Matveev // locked. 636cd571e07fd1179383188c70338fa0dc1c452cb19Sergey Matveev BlockingMutexLock l(&global_mutex); 637cd571e07fd1179383188c70338fa0dc1c452cb19Sergey Matveev IgnoreObjectResult res = IgnoreObjectLocked(p); 6382d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (res == kIgnoreObjectInvalid) 6392d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines VReport(1, "__lsan_ignore_object(): no heap object found at %p", p); 6402d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (res == kIgnoreObjectAlreadyIgnored) 6412d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines VReport(1, "__lsan_ignore_object(): " 642cd571e07fd1179383188c70338fa0dc1c452cb19Sergey Matveev "heap object at %p is already being ignored\n", p); 6432d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (res == kIgnoreObjectSuccess) 6442d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines VReport(1, "__lsan_ignore_object(): ignoring heap object at %p\n", p); 6452d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#endif // CAN_SANITIZE_LEAKS 6462d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines} 6472d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines 6482d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen HinesSANITIZER_INTERFACE_ATTRIBUTE 6492d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid __lsan_register_root_region(const void *begin, uptr size) { 6502d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#if CAN_SANITIZE_LEAKS 6512d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines BlockingMutexLock l(&global_mutex); 6522d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines CHECK(root_regions); 6532d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines RootRegion region = {begin, size}; 6542d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines root_regions->push_back(region); 6552d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines VReport(1, "Registered root region at %p of size %llu\n", begin, size); 6562d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#endif // CAN_SANITIZE_LEAKS 6572d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines} 6582d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines 6592d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen HinesSANITIZER_INTERFACE_ATTRIBUTE 6602d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid __lsan_unregister_root_region(const void *begin, uptr size) { 6612d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#if CAN_SANITIZE_LEAKS 6622d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines BlockingMutexLock l(&global_mutex); 6632d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines CHECK(root_regions); 6642d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines bool removed = false; 6652d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines for (uptr i = 0; i < root_regions->size(); i++) { 6662d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines RootRegion region = (*root_regions)[i]; 6672d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (region.begin == begin && region.size == size) { 6682d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines removed = true; 6692d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines uptr last_index = root_regions->size() - 1; 6702d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines (*root_regions)[i] = (*root_regions)[last_index]; 6712d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines root_regions->pop_back(); 6722d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines VReport(1, "Unregistered root region at %p of size %llu\n", begin, size); 6732d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines break; 6742d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines } 6752d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines } 6762d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (!removed) { 6772d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Report( 6782d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines "__lsan_unregister_root_region(): region at %p of size %llu has not " 6792d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines "been registered.\n", 6802d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines begin, size); 6812d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Die(); 6822d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines } 6839b618a7ec2ec78e602d8897008c6f02cba673794Sergey Matveev#endif // CAN_SANITIZE_LEAKS 684cd571e07fd1179383188c70338fa0dc1c452cb19Sergey Matveev} 685200afbd8ba4904241c1ebcef4fa79d739ca01f73Sergey Matveev 686200afbd8ba4904241c1ebcef4fa79d739ca01f73Sergey MatveevSANITIZER_INTERFACE_ATTRIBUTE 687200afbd8ba4904241c1ebcef4fa79d739ca01f73Sergey Matveevvoid __lsan_disable() { 688200afbd8ba4904241c1ebcef4fa79d739ca01f73Sergey Matveev#if CAN_SANITIZE_LEAKS 689200afbd8ba4904241c1ebcef4fa79d739ca01f73Sergey Matveev __lsan::disable_counter++; 690200afbd8ba4904241c1ebcef4fa79d739ca01f73Sergey Matveev#endif 691200afbd8ba4904241c1ebcef4fa79d739ca01f73Sergey Matveev} 692200afbd8ba4904241c1ebcef4fa79d739ca01f73Sergey Matveev 693200afbd8ba4904241c1ebcef4fa79d739ca01f73Sergey MatveevSANITIZER_INTERFACE_ATTRIBUTE 694200afbd8ba4904241c1ebcef4fa79d739ca01f73Sergey Matveevvoid __lsan_enable() { 695200afbd8ba4904241c1ebcef4fa79d739ca01f73Sergey Matveev#if CAN_SANITIZE_LEAKS 696137a9b84c25f1ad7d68a14f138cf270a03a738cbSergey Matveev if (!__lsan::disable_counter && common_flags()->detect_leaks) { 697200afbd8ba4904241c1ebcef4fa79d739ca01f73Sergey Matveev Report("Unmatched call to __lsan_enable().\n"); 698200afbd8ba4904241c1ebcef4fa79d739ca01f73Sergey Matveev Die(); 699200afbd8ba4904241c1ebcef4fa79d739ca01f73Sergey Matveev } 700200afbd8ba4904241c1ebcef4fa79d739ca01f73Sergey Matveev __lsan::disable_counter--; 701200afbd8ba4904241c1ebcef4fa79d739ca01f73Sergey Matveev#endif 702200afbd8ba4904241c1ebcef4fa79d739ca01f73Sergey Matveev} 7039fbfd96608070eb71e11fbfe42ec9e84016429aeAlexey Samsonov 704f93fa97b9fb49c6aaeeadf94fc54c76374b580bdSergey MatveevSANITIZER_INTERFACE_ATTRIBUTE 705f93fa97b9fb49c6aaeeadf94fc54c76374b580bdSergey Matveevvoid __lsan_do_leak_check() { 706f93fa97b9fb49c6aaeeadf94fc54c76374b580bdSergey Matveev#if CAN_SANITIZE_LEAKS 70762519eb72ec1005d794685c1ec09df7c37631b27Sergey Matveev if (common_flags()->detect_leaks) 70862519eb72ec1005d794685c1ec09df7c37631b27Sergey Matveev __lsan::DoLeakCheck(); 70962519eb72ec1005d794685c1ec09df7c37631b27Sergey Matveev#endif // CAN_SANITIZE_LEAKS 710f93fa97b9fb49c6aaeeadf94fc54c76374b580bdSergey Matveev} 711f93fa97b9fb49c6aaeeadf94fc54c76374b580bdSergey Matveev 7129fbfd96608070eb71e11fbfe42ec9e84016429aeAlexey Samsonov#if !SANITIZER_SUPPORTS_WEAK_HOOKS 7133c80c6c574850106481f82b9e23d1c728458d4a9Timur IskhodzhanovSANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE 7149fbfd96608070eb71e11fbfe42ec9e84016429aeAlexey Samsonovint __lsan_is_turned_off() { 7159fbfd96608070eb71e11fbfe42ec9e84016429aeAlexey Samsonov return 0; 7169fbfd96608070eb71e11fbfe42ec9e84016429aeAlexey Samsonov} 7179fbfd96608070eb71e11fbfe42ec9e84016429aeAlexey Samsonov#endif 718cd571e07fd1179383188c70338fa0dc1c452cb19Sergey Matveev} // extern "C" 719