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