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, &param->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, &param);
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