lsan_common.cc revision 6c3634b1d5eeb0bffea01df10caa7168c48c8c5d
18d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S//=-- lsan_common.cc ------------------------------------------------------===//
28d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S//
38d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S//                     The LLVM Compiler Infrastructure
48d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S//
58d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// This file is distributed under the University of Illinois Open Source
68d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// License. See LICENSE.TXT for details.
78d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S//
88d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S//===----------------------------------------------------------------------===//
98d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S//
108d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// This file is a part of LeakSanitizer.
118d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// Implementation of common leak checking functionality.
128d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S//
138d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S//===----------------------------------------------------------------------===//
148d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
158d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S#include "lsan_common.h"
168d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
178d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S#include "sanitizer_common/sanitizer_common.h"
188d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S#include "sanitizer_common/sanitizer_flags.h"
198d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S#include "sanitizer_common/sanitizer_stackdepot.h"
208d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S#include "sanitizer_common/sanitizer_stacktrace.h"
218d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S#include "sanitizer_common/sanitizer_stoptheworld.h"
228d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
238d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S#if CAN_SANITIZE_LEAKS
248d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Snamespace __lsan {
258d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
268d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha SFlags lsan_flags;
278d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
288d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Sstatic void InitializeFlags() {
298d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  Flags *f = flags();
308d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  // Default values.
318d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  f->sources = kSourceAllAligned;
328d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  f->report_blocks = false;
338d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  f->resolution = 0;
348d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  f->max_leaks = 0;
358d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  f->exitcode = 23;
368d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  f->log_pointers = false;
378d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  f->log_threads = false;
388d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
398d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  const char *options = GetEnv("LSAN_OPTIONS");
408d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  if (options) {
418d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    bool aligned = true;
428d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    ParseFlag(options, &aligned, "aligned");
438d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    if (!aligned) f->sources |= kSourceUnaligned;
448d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    ParseFlag(options, &f->report_blocks, "report_blocks");
458d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    ParseFlag(options, &f->resolution, "resolution");
468d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    CHECK_GE(&f->resolution, 0);
478d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    ParseFlag(options, &f->max_leaks, "max_leaks");
488d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    CHECK_GE(&f->max_leaks, 0);
498d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    ParseFlag(options, &f->log_pointers, "log_pointers");
508d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    ParseFlag(options, &f->log_threads, "log_threads");
518d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    ParseFlag(options, &f->exitcode, "exitcode");
528d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  }
538d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S}
548d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
558d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Svoid InitCommonLsan() {
568d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  InitializeFlags();
578d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  InitializePlatformSpecificModules();
588d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S}
598d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
608d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Sstatic inline bool CanBeAHeapPointer(uptr p) {
618d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  // Since our heap is located in mmap-ed memory, we can assume a sensible lower
628d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  // boundary on heap addresses.
638d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  const uptr kMinAddress = 4 * 4096;
648d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  if (p < kMinAddress) return false;
65134291ea0b1b9794b4d7feee2c3ffdbd941c5237Harinarayanan K K#ifdef __x86_64__
668d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  // Accept only canonical form user-space addresses.
678d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  return ((p >> 47) == 0);
688d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S#else
698d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  return true;
708d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S#endif
718d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S}
728d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
738d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// Scan the memory range, looking for byte patterns that point into allocator
748d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// chunks. Mark those chunks with tag and add them to the frontier.
758d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// There are two usage modes for this function: finding non-leaked chunks
768d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// (tag = kReachable) and finding indirectly leaked chunks
778d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// (tag = kIndirectlyLeaked). In the second case, there's no flood fill,
788d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// so frontier = 0.
798d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Svoid ScanRangeForPointers(uptr begin, uptr end, InternalVector<uptr> *frontier,
808d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S                          const char *region_type, ChunkTag tag) {
818d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  const uptr alignment = flags()->pointer_alignment();
828d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  if (flags()->log_pointers)
83134291ea0b1b9794b4d7feee2c3ffdbd941c5237Harinarayanan K K    Report("Scanning %s range %p-%p.\n", region_type, begin, end);
848d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  uptr pp = begin;
858d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  if (pp % alignment)
868d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    pp = pp + alignment - pp % alignment;
878d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  for (; pp + sizeof(uptr) <= end; pp += alignment) {
888d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    void *p = *reinterpret_cast<void**>(pp);
898d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    if (!CanBeAHeapPointer(reinterpret_cast<uptr>(p))) continue;
90134291ea0b1b9794b4d7feee2c3ffdbd941c5237Harinarayanan K K    // FIXME: PointsIntoChunk is SLOW because GetBlockBegin() in
918d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    // LargeMmapAllocator involves a lock and a linear search.
928d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    void *chunk = PointsIntoChunk(p);
938d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    if (!chunk) continue;
948d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    LsanMetadata m(chunk);
958d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    if (m.tag() == kReachable) continue;
968d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    m.set_tag(tag);
978d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    if (flags()->log_pointers)
988d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S      Report("%p: found %p pointing into chunk %p-%p of size %llu.\n", pp, p,
998d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S             chunk, reinterpret_cast<uptr>(chunk) + m.requested_size(),
1008d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S             m.requested_size());
1018d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    if (frontier)
1028d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S      frontier->push_back(reinterpret_cast<uptr>(chunk));
1038d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  }
1048d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S}
1058d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
1068d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// Scan thread data (stacks and TLS) for heap pointers.
1078d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Sstatic void ProcessThreads(SuspendedThreadsList const &suspended_threads,
1088d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S                           InternalVector<uptr> *frontier) {
1098d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  InternalScopedBuffer<uptr> registers(SuspendedThreadsList::RegisterCount());
1108d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  uptr registers_begin = reinterpret_cast<uptr>(registers.data());
1118d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  uptr registers_end = registers_begin + registers.size();
1128d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  for (uptr i = 0; i < suspended_threads.thread_count(); i++) {
1138d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    uptr os_id = static_cast<uptr>(suspended_threads.GetThreadID(i));
1148d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    if (flags()->log_threads) Report("Processing thread %d.\n", os_id);
1158d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    uptr stack_begin, stack_end, tls_begin, tls_end, cache_begin, cache_end;
1168d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    bool thread_found = GetThreadRangesLocked(os_id, &stack_begin, &stack_end,
1178d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S                                              &tls_begin, &tls_end,
1188d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S                                              &cache_begin, &cache_end);
1198d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    if (!thread_found) {
1208d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S      // If a thread can't be found in the thread registry, it's probably in the
1218d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S      // process of destruction. Log this event and move on.
1228d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S      if (flags()->log_threads)
1238d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S        Report("Thread %d not found in registry.\n", os_id);
1248d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S      continue;
1258d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    }
1268d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    uptr sp;
1278d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    bool have_registers =
1288d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S        (suspended_threads.GetRegistersAndSP(i, registers.data(), &sp) == 0);
1298d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    if (!have_registers) {
1308d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S      Report("Unable to get registers from thread %d.\n");
1318d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S      // If unable to get SP, consider the entire stack to be reachable.
1328d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S      sp = stack_begin;
1338d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    }
1348d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
1358d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    if (flags()->use_registers() && have_registers)
1368d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S      ScanRangeForPointers(registers_begin, registers_end, frontier,
1378d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S                           "REGISTERS", kReachable);
1388d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
1398d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    if (flags()->use_stacks()) {
1408d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S      if (flags()->log_threads)
1418d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S        Report("Stack at %p-%p, SP = %p.\n", stack_begin, stack_end, sp);
1428d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S      if (sp < stack_begin || sp >= stack_end) {
1438d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S        // SP is outside the recorded stack range (e.g. the thread is running a
1448d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S        // signal handler on alternate stack). Again, consider the entire stack
1458d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S        // range to be reachable.
1468d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S        if (flags()->log_threads)
1478d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S          Report("WARNING: stack_pointer not in stack_range.\n");
1488d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S      } else {
1498d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S        // Shrink the stack range to ignore out-of-scope values.
1508d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S        stack_begin = sp;
1518d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S      }
1528d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S      ScanRangeForPointers(stack_begin, stack_end, frontier, "STACK",
1538d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S                           kReachable);
1548d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    }
1558d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
1568d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    if (flags()->use_tls()) {
1578d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S      if (flags()->log_threads) Report("TLS at %p-%p.\n", tls_begin, tls_end);
1588d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S      // Because LSan should not be loaded with dlopen(), we can assume
1598d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S      // that allocator cache will be part of static TLS image.
1608d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S      CHECK_LE(tls_begin, cache_begin);
1618d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S      CHECK_GE(tls_end, cache_end);
1628d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S      if (tls_begin < cache_begin)
1638d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S        ScanRangeForPointers(tls_begin, cache_begin, frontier, "TLS",
1648d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S                             kReachable);
1658d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S      if (tls_end > cache_end)
1668d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S        ScanRangeForPointers(cache_end, tls_end, frontier, "TLS", kReachable);
1678d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    }
1688d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  }
1698d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S}
1708d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
1718d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Sstatic void FloodFillReachable(InternalVector<uptr> *frontier) {
1728d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  while (frontier->size()) {
1738d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    uptr next_chunk = frontier->back();
1748d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    frontier->pop_back();
1758d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    LsanMetadata m(reinterpret_cast<void *>(next_chunk));
1768d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    ScanRangeForPointers(next_chunk, next_chunk + m.requested_size(), frontier,
1778d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S                         "HEAP", kReachable);
1788d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  }
1798d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S}
1808d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
1818d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// Mark leaked chunks which are reachable from other leaked chunks.
1828d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Svoid MarkIndirectlyLeakedCb::operator()(void *p) const {
1838d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  p = GetUserBegin(p);
1848d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  LsanMetadata m(p);
1858d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  if (m.allocated() && m.tag() != kReachable) {
1868d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    ScanRangeForPointers(reinterpret_cast<uptr>(p),
1878d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S                         reinterpret_cast<uptr>(p) + m.requested_size(),
1888d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S                         /* frontier */ 0, "HEAP", kIndirectlyLeaked);
1898d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  }
1908d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S}
1918d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
1928d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// Set the appropriate tag on each chunk.
1938d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Sstatic void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads) {
1948d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  // Holds the flood fill frontier.
1958d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  InternalVector<uptr> frontier(GetPageSizeCached());
1968d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
1978d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  if (flags()->use_globals())
1988d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    ProcessGlobalRegions(&frontier);
1998d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  ProcessThreads(suspended_threads, &frontier);
2008d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  FloodFillReachable(&frontier);
2018d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  ProcessPlatformSpecificAllocations(&frontier);
2028d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  FloodFillReachable(&frontier);
2038d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
2048d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  // Now all reachable chunks are marked. Iterate over leaked chunks and mark
2058d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  // those that are reachable from other leaked chunks.
2068d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  if (flags()->log_pointers)
2078d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    Report("Now scanning leaked blocks for pointers.\n");
2088d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  ForEachChunk(MarkIndirectlyLeakedCb());
2098d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S}
2108d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
2118d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Svoid ClearTagCb::operator()(void *p) const {
2128d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  p = GetUserBegin(p);
2138d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  LsanMetadata m(p);
2148d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  m.set_tag(kDirectlyLeaked);
2158d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S}
2168d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
2178d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Sstatic void PrintStackTraceById(u32 stack_trace_id) {
2188d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  CHECK(stack_trace_id);
2198d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  uptr size = 0;
2208d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  const uptr *trace = StackDepotGet(stack_trace_id, &size);
2218d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  StackTrace::PrintStack(trace, size, common_flags()->symbolize,
2228d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S                         common_flags()->strip_path_prefix, 0);
2238d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S}
2248d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
2258d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Sstatic void LockAndSuspendThreads(StopTheWorldCallback callback, void *arg) {
2268d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  LockThreadRegistry();
2278d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  LockAllocator();
2288d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  StopTheWorld(callback, arg);
2298d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  // Allocator must be unlocked by the callback.
2308d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  UnlockThreadRegistry();
2318d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S}
2328d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
2338d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S///// Normal leak checking. /////
2348d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
2358d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Svoid CollectLeaksCb::operator()(void *p) const {
2368d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  p = GetUserBegin(p);
2378d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  LsanMetadata m(p);
2388d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  if (!m.allocated()) return;
2398d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  if (m.tag() != kReachable) {
2408d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    uptr resolution = flags()->resolution;
2418d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    if (resolution > 0) {
2428d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S      uptr size = 0;
2438d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S      const uptr *trace = StackDepotGet(m.stack_trace_id(), &size);
2448d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S      size = Min(size, resolution);
2458d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S      leak_report_->Add(StackDepotPut(trace, size), m.requested_size(),
2468d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S                        m.tag());
2478d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    } else {
2488d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S      leak_report_->Add(m.stack_trace_id(), m.requested_size(), m.tag());
2498d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    }
2508d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  }
2518d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S}
2528d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
2538d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Sstatic void CollectLeaks(LeakReport *leak_report) {
2548d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  ForEachChunk(CollectLeaksCb(leak_report));
2558d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S}
2568d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
2578d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Svoid PrintLeakedCb::operator()(void *p) const {
2588d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  p = GetUserBegin(p);
2598d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  LsanMetadata m(p);
2608d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  if (!m.allocated()) return;
2618d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  if (m.tag() != kReachable) {
2628d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    CHECK(m.tag() == kDirectlyLeaked || m.tag() == kIndirectlyLeaked);
2638d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    Printf("%s leaked %llu byte block at %p\n",
2648d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S           m.tag() == kDirectlyLeaked ? "Directly" : "Indirectly",
2658d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S           m.requested_size(), p);
2668d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  }
2678d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S}
2688d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
2698d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Sstatic void PrintLeaked() {
2708d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  Printf("Reporting individual blocks:\n");
2718d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  Printf("============================\n");
2728d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  ForEachChunk(PrintLeakedCb());
2738d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  Printf("\n");
2748d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S}
2758d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
2768d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Senum LeakCheckResult {
2778d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  kFatalError,
2788d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  kLeaksFound,
2798d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  kNoLeaks
2808d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S};
2818d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
2828d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Sstatic void DoLeakCheckCallback(const SuspendedThreadsList &suspended_threads,
2838d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S                                void *arg) {
2848d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  LeakCheckResult *result = reinterpret_cast<LeakCheckResult *>(arg);
2858d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  CHECK_EQ(*result, kFatalError);
2868d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  // Allocator must not be locked when we call GetRegionBegin().
2878d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  UnlockAllocator();
2888d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  ClassifyAllChunks(suspended_threads);
2898d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  LeakReport leak_report;
2908d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  CollectLeaks(&leak_report);
2918d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  if (leak_report.IsEmpty()) {
2928d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    *result = kNoLeaks;
2938d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    return;
2948d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  }
2958d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  Printf("\n");
2968d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  Printf("=================================================================\n");
2978d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  Report("ERROR: LeakSanitizer: detected leaks.\n");
2988d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  leak_report.PrintLargest(flags()->max_leaks);
2998d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  if (flags()->report_blocks)
3008d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    PrintLeaked();
3018d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  leak_report.PrintSummary();
3028d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  Printf("\n");
3038d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  ForEachChunk(ClearTagCb());
3048d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  *result = kLeaksFound;
3058d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S}
3068d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
3078d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Svoid DoLeakCheck() {
3088d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  LeakCheckResult result = kFatalError;
3098d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  LockAndSuspendThreads(DoLeakCheckCallback, &result);
3108d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  if (result == kFatalError) {
3118d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    Report("LeakSanitizer has encountered a fatal error.\n");
3128d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    Die();
3138d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  } else if (result == kLeaksFound) {
3148d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    if (flags()->exitcode)
3158d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S      internal__exit(flags()->exitcode);
3168d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  }
3178d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S}
3188d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
3198d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S///// Reporting of leaked blocks' addresses (for testing). /////
3208d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
3218d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Svoid ReportLeakedCb::operator()(void *p) const {
3228d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  p = GetUserBegin(p);
3238d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  LsanMetadata m(p);
3248d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  if (m.allocated() && m.tag() != kReachable)
3258d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    leaked_->push_back(p);
3268d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S}
3278d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
3288d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Sstruct ReportLeakedParam {
3298d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  InternalVector<void *> *leaked;
3308d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  uptr sources;
3318d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  bool success;
3328d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S};
3337313602decf30364e4823f6a9c34045432f0bd9fMartin Storsjo
3348d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Sstatic void ReportLeakedCallback(const SuspendedThreadsList &suspended_threads,
3358d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S                                 void *arg) {
3368d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  // Allocator must not be locked when we call GetRegionBegin().
3378d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  UnlockAllocator();
3388d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  ReportLeakedParam *param = reinterpret_cast<ReportLeakedParam *>(arg);
3398d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  flags()->sources = param->sources;
3408d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  ClassifyAllChunks(suspended_threads);
3418d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  ForEachChunk(ReportLeakedCb(param->leaked));
3428d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  ForEachChunk(ClearTagCb());
3438d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  param->success = true;
3448d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S}
3458d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
3468d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Svoid ReportLeaked(InternalVector<void *> *leaked, uptr sources) {
3478d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  CHECK_EQ(0, leaked->size());
3488d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  ReportLeakedParam param;
3498d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  param.leaked = leaked;
3508d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  param.success = false;
3518d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  param.sources = sources;
3528d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  LockAndSuspendThreads(ReportLeakedCallback, &param);
3538d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  CHECK(param.success);
3548d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S}
3558d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
3568d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S///// LeakReport implementation. /////
3578d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
3588d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// A hard limit on the number of distinct leaks, to avoid quadratic complexity
3598d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// in LeakReport::Add(). We don't expect to ever see this many leaks in
3608d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// real-world applications.
3618d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// FIXME: Get rid of this limit by changing the implementation of LeakReport to
3628d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S// use a hash table.
3638d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Sconst uptr kMaxLeaksConsidered = 1000;
3648d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
3658d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Svoid LeakReport::Add(u32 stack_trace_id, uptr leaked_size, ChunkTag tag) {
3668d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  CHECK(tag == kDirectlyLeaked || tag == kIndirectlyLeaked);
3678d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  bool is_directly_leaked = (tag == kDirectlyLeaked);
3688d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  for (uptr i = 0; i < leaks_.size(); i++)
3698d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    if (leaks_[i].stack_trace_id == stack_trace_id &&
3708d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S        leaks_[i].is_directly_leaked == is_directly_leaked) {
3718d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S      leaks_[i].hit_count++;
3728d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S      leaks_[i].total_size += leaked_size;
3738d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S      return;
3748d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    }
3758d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  if (leaks_.size() == kMaxLeaksConsidered) return;
3768d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  Leak leak = { /* hit_count */ 1, leaked_size, stack_trace_id,
3778d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S                is_directly_leaked };
3788d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  leaks_.push_back(leak);
3798d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S}
3808d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
3818d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Sstatic bool IsLarger(const Leak &leak1, const Leak &leak2) {
3828d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  return leak1.total_size > leak2.total_size;
3838d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S}
3848d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S
3858d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha Svoid LeakReport::PrintLargest(uptr max_leaks) {
3868d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  CHECK(leaks_.size() <= kMaxLeaksConsidered);
3878d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  Printf("\n");
3888d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  if (leaks_.size() == kMaxLeaksConsidered)
3898d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    Printf("Too many leaks! Only the first %llu leaks encountered will be "
3908d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S           "reported.\n",
3918d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S           kMaxLeaksConsidered);
3928d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S  if (max_leaks > 0 && max_leaks < leaks_.size())
3938d3d303c7942ced6a987a52db8977d768dc3605fHamsalekha S    Printf("The %llu largest leak%s:\n", max_leaks, max_leaks > 1 ? "s" : "");
394  InternalSort(&leaks_, leaks_.size(), IsLarger);
395  max_leaks = max_leaks > 0 ? Min(max_leaks, leaks_.size()) : leaks_.size();
396  for (uptr i = 0; i < max_leaks; i++) {
397    Printf("%s leak of %llu bytes in %llu object%s allocated from:\n",
398           leaks_[i].is_directly_leaked ? "Direct" : "Indirect",
399           leaks_[i].total_size, leaks_[i].hit_count,
400           leaks_[i].hit_count == 1 ? "" : "s");
401    PrintStackTraceById(leaks_[i].stack_trace_id);
402    Printf("\n");
403  }
404  if (max_leaks < leaks_.size()) {
405    uptr remaining = leaks_.size() - max_leaks;
406    Printf("Omitting %llu more leak%s.\n", remaining,
407           remaining > 1 ? "s" : "");
408  }
409}
410
411void LeakReport::PrintSummary() {
412  CHECK(leaks_.size() <= kMaxLeaksConsidered);
413  uptr bytes_leaked = 0;
414  for (uptr i = 0; i < leaks_.size(); i++) {
415      bytes_leaked += leaks_[i].total_size;
416  }
417  Printf("SUMMARY: LeakSanitizer: %llu bytes leaked.\n", bytes_leaked);
418}
419}  // namespace __lsan
420#endif  // CAN_SANITIZE_LEAKS
421