lsan_common.cc revision 2946f13d6ca0cfc46d74c12e97dc40a17a7d232f
108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project//=-- lsan_common.cc ------------------------------------------------------===// 208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project// 308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project// The LLVM Compiler Infrastructure 408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project// 508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project// This file is distributed under the University of Illinois Open Source 608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project// License. See LICENSE.TXT for details. 708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project// 808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project//===----------------------------------------------------------------------===// 908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project// 1008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project// This file is a part of LeakSanitizer. 1108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project// Implementation of common leak checking functionality. 1208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project// 1308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project//===----------------------------------------------------------------------===// 1408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 1508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project#include "lsan_common.h" 1608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 17860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root#include "sanitizer_common/sanitizer_common.h" 1808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project#include "sanitizer_common/sanitizer_flags.h" 1990ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom#include "sanitizer_common/sanitizer_placement_new.h" 20f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom#include "sanitizer_common/sanitizer_stackdepot.h" 21d05ac5ff95fa7d673de209a780d5f9b4f106e50dKenny Root#include "sanitizer_common/sanitizer_stacktrace.h" 22f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom#include "sanitizer_common/sanitizer_stoptheworld.h" 236224c2e60c987d560cb5d76aa6af4c185ce87768Brian Carlstrom#include "sanitizer_common/sanitizer_suppressions.h" 246224c2e60c987d560cb5d76aa6af4c185ce87768Brian Carlstrom#include "sanitizer_common/sanitizer_report_decorator.h" 25f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root 26f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root#if CAN_SANITIZE_LEAKS 27f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Rootnamespace __lsan { 28f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root 29098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom// This mutex is used to prevent races between DoLeakCheck and IgnoreObject. 30f52606090f0f7160c2c7a85069959c1124151d79Brian CarlstromBlockingMutex global_mutex(LINKER_INITIALIZED); 312828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom 3236e383e2f9c447e05adcca4426d8b33b2ef73ca7Kenny RootTHREADLOCAL int disable_counter; 33f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Rootbool DisabledInThisThread() { return disable_counter > 0; } 34f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root 35f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny RootFlags lsan_flags; 362828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom 3732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootstatic void InitializeFlags() { 3861b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom Flags *f = flags(); 3961b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom // Default values. 4061b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom f->report_objects = false; 4161b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom f->resolution = 0; 42098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom f->max_leaks = 0; 43f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root f->exitcode = 23; 44987b13e30fa7fe65c2b84a47f181a29484cc89dcKenny Root f->suppressions=""; 45f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root f->use_registers = true; 46f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom f->use_globals = true; 476224c2e60c987d560cb5d76aa6af4c185ce87768Brian Carlstrom f->use_stacks = true; 48f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom f->use_tls = true; 4908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project f->use_unaligned = false; 501f42e0a4d7d28b8fc20833e0be05ad17dcfa8ea0Brian Carlstrom f->verbosity = 0; 5108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project f->log_pointers = false; 521f42e0a4d7d28b8fc20833e0be05ad17dcfa8ea0Brian Carlstrom f->log_threads = false; 5308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 54f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom const char *options = GetEnv("LSAN_OPTIONS"); 5508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project if (options) { 56923e3c5a80a6daefc14d4d0242ac46f23ac41b6aKenny Root ParseFlag(options, &f->use_registers, "use_registers"); 57eaeedc318b5fba9995fc64d15341017ec182fe4cKenny Root ParseFlag(options, &f->use_globals, "use_globals"); 58eaeedc318b5fba9995fc64d15341017ec182fe4cKenny Root ParseFlag(options, &f->use_stacks, "use_stacks"); 59923e3c5a80a6daefc14d4d0242ac46f23ac41b6aKenny Root ParseFlag(options, &f->use_tls, "use_tls"); 60eaeedc318b5fba9995fc64d15341017ec182fe4cKenny Root ParseFlag(options, &f->use_unaligned, "use_unaligned"); 61eaeedc318b5fba9995fc64d15341017ec182fe4cKenny Root ParseFlag(options, &f->report_objects, "report_objects"); 62e66dbe5ad60417a4a9bf5ddf0bc3eb02652e43c8Justin Morey ParseFlag(options, &f->resolution, "resolution"); 63e66dbe5ad60417a4a9bf5ddf0bc3eb02652e43c8Justin Morey CHECK_GE(&f->resolution, 0); 64e66dbe5ad60417a4a9bf5ddf0bc3eb02652e43c8Justin Morey ParseFlag(options, &f->max_leaks, "max_leaks"); 65eaeedc318b5fba9995fc64d15341017ec182fe4cKenny Root CHECK_GE(&f->max_leaks, 0); 66923e3c5a80a6daefc14d4d0242ac46f23ac41b6aKenny Root ParseFlag(options, &f->verbosity, "verbosity"); 67923e3c5a80a6daefc14d4d0242ac46f23ac41b6aKenny Root ParseFlag(options, &f->log_pointers, "log_pointers"); 68923e3c5a80a6daefc14d4d0242ac46f23ac41b6aKenny Root ParseFlag(options, &f->log_threads, "log_threads"); 69f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom ParseFlag(options, &f->exitcode, "exitcode"); 7008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project ParseFlag(options, &f->suppressions, "suppressions"); 7108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 72f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom} 73f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom 74a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny RootSuppressionContext *suppression_ctx; 75a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root 76a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Rootvoid InitializeSuppressions() { 7738c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice CHECK(!suppression_ctx); 78a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root ALIGNED(64) static char placeholder_[sizeof(SuppressionContext)]; 7938c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice suppression_ctx = new(placeholder_) SuppressionContext; 8061baefce87ed97b30e316469d69715503eea8996Kenny Root char *suppressions_from_file; 8138c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice uptr buffer_size; 82a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root if (ReadFileToBuffer(flags()->suppressions, &suppressions_from_file, 8338c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice &buffer_size, 1 << 26 /* max_len */)) 84a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root suppression_ctx->Parse(suppressions_from_file); 8538c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice if (flags()->suppressions[0] && !buffer_size) { 86a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root Printf("LeakSanitizer: failed to read suppressions file '%s'\n", 8738c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice flags()->suppressions); 88a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root Die(); 8938c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice } 9047cc520bd63c1eabfdef23cbab10457701f2a395Kenny Root if (&__lsan_default_suppressions) 9138c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice suppression_ctx->Parse(__lsan_default_suppressions()); 920084d3b527f2da12fab2ed45914f172b84e50c20Kenny Root} 930084d3b527f2da12fab2ed45914f172b84e50c20Kenny Root 9408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectvoid InitCommonLsan() { 95f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom InitializeFlags(); 9638c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice InitializeSuppressions(); 9738c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice InitializePlatformSpecificModules(); 9808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project} 9938c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice 100aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Rootclass Decorator: private __sanitizer::AnsiColorDecorator { 101f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom public: 10238c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice Decorator() : __sanitizer::AnsiColorDecorator(PrintsToTtyCached()) { } 103e4b82368b271aa959783814dde0087c84aed53b5Kenny Root const char *Error() { return Red(); } 10438c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice const char *Leak() { return Blue(); } 105bad843cfc413e5ccb61bacc426a204def0687e69Kenny Root const char *End() { return Default(); } 10638c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice}; 107a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root 10838c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dicestatic inline bool CanBeAHeapPointer(uptr p) { 1098b7521eb38878822be3817270cc074ee1e22095dKenny Root // Since our heap is located in mmap-ed memory, we can assume a sensible lower 11038c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice // bound on heap addresses. 1118b7521eb38878822be3817270cc074ee1e22095dKenny Root const uptr kMinAddress = 4 * 4096; 11238c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice if (p < kMinAddress) return false; 113f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom#ifdef __x86_64__ 11438c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice // Accept only canonical form user-space addresses. 11534558f485bbfe7ca12622f59427321da11cb108dKenny Root return ((p >> 47) == 0); 11638c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice#else 117aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root return true; 11838c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice#endif 119aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root} 12038c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice 121aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root// Scans the memory range, looking for byte patterns that point into allocator 12238c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice// chunks. Marks those chunks with |tag| and adds them to |frontier|. 123aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root// There are two usage modes for this function: finding reachable or ignored 124f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root// chunks (|tag| = kReachable or kIgnored) and finding indirectly leaked chunks 125f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root// (|tag| = kIndirectlyLeaked). In the second case, there's no flood fill, 126f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root// so |frontier| = 0. 127f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Rootvoid ScanRangeForPointers(uptr begin, uptr end, 128f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root Frontier *frontier, 129f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root const char *region_type, ChunkTag tag) { 13038c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice const uptr alignment = flags()->pointer_alignment(); 131aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root if (flags()->log_pointers) 13238c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice Report("Scanning %s range %p-%p.\n", region_type, begin, end); 1336e7efe14188211dc0f8a2e08276556e871fd8748Kenny Root uptr pp = begin; 13438c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice if (pp % alignment) 1356e7efe14188211dc0f8a2e08276556e871fd8748Kenny Root pp = pp + alignment - pp % alignment; 1366e7efe14188211dc0f8a2e08276556e871fd8748Kenny Root for (; pp + sizeof(void *) <= end; pp += alignment) { // NOLINT 13738c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice void *p = *reinterpret_cast<void **>(pp); 138098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom if (!CanBeAHeapPointer(reinterpret_cast<uptr>(p))) continue; 1396e7efe14188211dc0f8a2e08276556e871fd8748Kenny Root uptr chunk = PointsIntoChunk(p); 14038c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice if (!chunk) continue; 141098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom LsanMetadata m(chunk); 1426e7efe14188211dc0f8a2e08276556e871fd8748Kenny Root // Reachable beats ignored beats leaked. 14338c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice if (m.tag() == kReachable) continue; 144098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom if (m.tag() == kIgnored && tag != kReachable) continue; 1456e7efe14188211dc0f8a2e08276556e871fd8748Kenny Root m.set_tag(tag); 146aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root if (flags()->log_pointers) 147aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root Report("%p: found %p pointing into chunk %p-%p of size %zu.\n", pp, p, 148aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root chunk, chunk + m.requested_size(), m.requested_size()); 14938c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice if (frontier) 150aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root frontier->push_back(chunk); 151aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root } 152aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root} 153aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root 15438c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice// Scans thread data (stacks and TLS) for heap pointers. 155aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Rootstatic void ProcessThreads(SuspendedThreadsList const &suspended_threads, 15638c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice Frontier *frontier) { 157aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root InternalScopedBuffer<uptr> registers(SuspendedThreadsList::RegisterCount()); 158aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root uptr registers_begin = reinterpret_cast<uptr>(registers.data()); 159aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root uptr registers_end = registers_begin + registers.size(); 160aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root for (uptr i = 0; i < suspended_threads.thread_count(); i++) { 161aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root uptr os_id = static_cast<uptr>(suspended_threads.GetThreadID(i)); 16238c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice if (flags()->log_threads) Report("Processing thread %d.\n", os_id); 163aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root uptr stack_begin, stack_end, tls_begin, tls_end, cache_begin, cache_end; 16460f83802801e224b51afac6c27c19e7c3d65ddc3Alex Klyubin bool thread_found = GetThreadRangesLocked(os_id, &stack_begin, &stack_end, 16560f83802801e224b51afac6c27c19e7c3d65ddc3Alex Klyubin &tls_begin, &tls_end, 16638c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice &cache_begin, &cache_end); 167aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root if (!thread_found) { 16838c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice // If a thread can't be found in the thread registry, it's probably in the 169aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root // process of destruction. Log this event and move on. 17038c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice if (flags()->log_threads) 171aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root Report("Thread %d not found in registry.\n", os_id); 17238c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice continue; 173aa48fdb4d42bc5de668f11055f88fb430fdf4d61Kenny Root } 1747b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root uptr sp; 1757b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root bool have_registers = 1767b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root (suspended_threads.GetRegistersAndSP(i, registers.data(), &sp) == 0); 1777b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root if (!have_registers) { 1787b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root Report("Unable to get registers from thread %d.\n"); 1797b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root // If unable to get SP, consider the entire stack to be reachable. 1807b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root sp = stack_begin; 1817b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root } 1827b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root 1837b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root if (flags()->use_registers && have_registers) 1847b27ca77c328e510a165712a497c20b67c68e8a3Kenny Root ScanRangeForPointers(registers_begin, registers_end, frontier, 1858b7521eb38878822be3817270cc074ee1e22095dKenny Root "REGISTERS", kReachable); 1868b7521eb38878822be3817270cc074ee1e22095dKenny Root 1878b7521eb38878822be3817270cc074ee1e22095dKenny Root if (flags()->use_stacks) { 1888b7521eb38878822be3817270cc074ee1e22095dKenny Root if (flags()->log_threads) 1898b7521eb38878822be3817270cc074ee1e22095dKenny Root Report("Stack at %p-%p, SP = %p.\n", stack_begin, stack_end, sp); 1908b7521eb38878822be3817270cc074ee1e22095dKenny Root if (sp < stack_begin || sp >= stack_end) { 1918b7521eb38878822be3817270cc074ee1e22095dKenny Root // SP is outside the recorded stack range (e.g. the thread is running a 1928b7521eb38878822be3817270cc074ee1e22095dKenny Root // signal handler on alternate stack). Again, consider the entire stack 1938b7521eb38878822be3817270cc074ee1e22095dKenny Root // range to be reachable. 1948b7521eb38878822be3817270cc074ee1e22095dKenny Root if (flags()->log_threads) 1958b7521eb38878822be3817270cc074ee1e22095dKenny Root Report("WARNING: stack pointer not in stack range.\n"); 1968b7521eb38878822be3817270cc074ee1e22095dKenny Root } else { 197c6e93518bda6c5bc2959641711eca9d9078fb530Kenny Root // Shrink the stack range to ignore out-of-scope values. 198c6e93518bda6c5bc2959641711eca9d9078fb530Kenny Root stack_begin = sp; 199c6e93518bda6c5bc2959641711eca9d9078fb530Kenny Root } 200c6e93518bda6c5bc2959641711eca9d9078fb530Kenny Root ScanRangeForPointers(stack_begin, stack_end, frontier, "STACK", 201c6e93518bda6c5bc2959641711eca9d9078fb530Kenny Root kReachable); 202c6e93518bda6c5bc2959641711eca9d9078fb530Kenny Root } 203c6e93518bda6c5bc2959641711eca9d9078fb530Kenny Root 204c6e93518bda6c5bc2959641711eca9d9078fb530Kenny Root if (flags()->use_tls) { 205c6e93518bda6c5bc2959641711eca9d9078fb530Kenny Root if (flags()->log_threads) Report("TLS at %p-%p.\n", tls_begin, tls_end); 206c6e93518bda6c5bc2959641711eca9d9078fb530Kenny Root if (cache_begin == cache_end) { 207c6e93518bda6c5bc2959641711eca9d9078fb530Kenny Root ScanRangeForPointers(tls_begin, tls_end, frontier, "TLS", kReachable); 208c6e93518bda6c5bc2959641711eca9d9078fb530Kenny Root } else { 209c6e93518bda6c5bc2959641711eca9d9078fb530Kenny Root // Because LSan should not be loaded with dlopen(), we can assume 210c6e93518bda6c5bc2959641711eca9d9078fb530Kenny Root // that allocator cache will be part of static TLS image. 211c6e93518bda6c5bc2959641711eca9d9078fb530Kenny Root CHECK_LE(tls_begin, cache_begin); 212c6e93518bda6c5bc2959641711eca9d9078fb530Kenny Root CHECK_GE(tls_end, cache_end); 213c6e93518bda6c5bc2959641711eca9d9078fb530Kenny Root if (tls_begin < cache_begin) 214c6e93518bda6c5bc2959641711eca9d9078fb530Kenny Root ScanRangeForPointers(tls_begin, cache_begin, frontier, "TLS", 215c6e93518bda6c5bc2959641711eca9d9078fb530Kenny Root kReachable); 216c6e93518bda6c5bc2959641711eca9d9078fb530Kenny Root if (tls_end > cache_end) 21738c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice ScanRangeForPointers(cache_end, tls_end, frontier, "TLS", kReachable); 2188b7521eb38878822be3817270cc074ee1e22095dKenny Root } 21938c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice } 2208b7521eb38878822be3817270cc074ee1e22095dKenny Root } 22138c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice} 2228b7521eb38878822be3817270cc074ee1e22095dKenny Root 22338c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dicestatic void FloodFillTag(Frontier *frontier, ChunkTag tag) { 22447cc520bd63c1eabfdef23cbab10457701f2a395Kenny Root while (frontier->size()) { 22538c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice uptr next_chunk = frontier->back(); 226c6e93518bda6c5bc2959641711eca9d9078fb530Kenny Root frontier->pop_back(); 22738c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice LsanMetadata m(next_chunk); 228c6e93518bda6c5bc2959641711eca9d9078fb530Kenny Root ScanRangeForPointers(next_chunk, next_chunk + m.requested_size(), frontier, 22938c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice "HEAP", tag); 230c6e93518bda6c5bc2959641711eca9d9078fb530Kenny Root } 23138c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice} 2328b7521eb38878822be3817270cc074ee1e22095dKenny Root 23338c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice// ForEachChunk callback. If the chunk is marked as leaked, marks all chunks 2348b7521eb38878822be3817270cc074ee1e22095dKenny Root// which are reachable from it as indirectly leaked. 23538c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dicestatic void MarkIndirectlyLeakedCb(uptr chunk, void *arg) { 2368b7521eb38878822be3817270cc074ee1e22095dKenny Root chunk = GetUserBegin(chunk); 23738c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice LsanMetadata m(chunk); 2388b7521eb38878822be3817270cc074ee1e22095dKenny Root if (m.allocated() && m.tag() != kReachable) { 23938c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice ScanRangeForPointers(chunk, chunk + m.requested_size(), 2408b7521eb38878822be3817270cc074ee1e22095dKenny Root /* frontier */ 0, "HEAP", kIndirectlyLeaked); 24138c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice } 2428b7521eb38878822be3817270cc074ee1e22095dKenny Root} 24338c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice 2448b7521eb38878822be3817270cc074ee1e22095dKenny Root// ForEachChunk callback. If chunk is marked as ignored, adds its address to 245d5107430b8606db5b49f2857c290c783082bbed3Alex Klyubin// frontier. 246d5107430b8606db5b49f2857c290c783082bbed3Alex Klyubinstatic void CollectIgnoredCb(uptr chunk, void *arg) { 24738c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice CHECK(arg); 2488b7521eb38878822be3817270cc074ee1e22095dKenny Root chunk = GetUserBegin(chunk); 24938c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice LsanMetadata m(chunk); 2508b7521eb38878822be3817270cc074ee1e22095dKenny Root if (m.allocated() && m.tag() == kIgnored) 25138c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice reinterpret_cast<Frontier *>(arg)->push_back(chunk); 2528b7521eb38878822be3817270cc074ee1e22095dKenny Root} 25338c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice 2548b7521eb38878822be3817270cc074ee1e22095dKenny Root// Sets the appropriate tag on each chunk. 25538c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dicestatic void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads) { 2568b7521eb38878822be3817270cc074ee1e22095dKenny Root // Holds the flood fill frontier. 25738c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice Frontier frontier(GetPageSizeCached()); 2588b7521eb38878822be3817270cc074ee1e22095dKenny Root 2598b7521eb38878822be3817270cc074ee1e22095dKenny Root if (flags()->use_globals) 26038c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice ProcessGlobalRegions(&frontier); 2618b7521eb38878822be3817270cc074ee1e22095dKenny Root ProcessThreads(suspended_threads, &frontier); 26238c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice FloodFillTag(&frontier, kReachable); 263c6e93518bda6c5bc2959641711eca9d9078fb530Kenny Root // The check here is relatively expensive, so we do this in a separate flood 26438c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice // fill. That way we can skip the check for chunks that are reachable 2658b7521eb38878822be3817270cc074ee1e22095dKenny Root // otherwise. 26638c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice ProcessPlatformSpecificAllocations(&frontier); 2678b7521eb38878822be3817270cc074ee1e22095dKenny Root FloodFillTag(&frontier, kReachable); 26860f83802801e224b51afac6c27c19e7c3d65ddc3Alex Klyubin 26960f83802801e224b51afac6c27c19e7c3d65ddc3Alex Klyubin if (flags()->log_pointers) 27082f6e22581a00a2acaaa932cf471e276d696965bAlex Klyubin Report("Scanning ignored chunks.\n"); 27182f6e22581a00a2acaaa932cf471e276d696965bAlex Klyubin CHECK_EQ(0, frontier.size()); 27282f6e22581a00a2acaaa932cf471e276d696965bAlex Klyubin ForEachChunk(CollectIgnoredCb, &frontier); 273079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom FloodFillTag(&frontier, kIgnored); 274f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom 27538c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice // Iterate over leaked chunks and mark those that are reachable from other 276079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom // leaked chunks. 27738c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice if (flags()->log_pointers) 278079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom Report("Scanning leaked chunks.\n"); 27938c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice ForEachChunk(MarkIndirectlyLeakedCb, 0 /* arg */); 280079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom} 281079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom 282f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstromstatic void PrintStackTraceById(u32 stack_trace_id) { 28338c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice CHECK(stack_trace_id); 284e4b82368b271aa959783814dde0087c84aed53b5Kenny Root uptr size = 0; 285652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root const uptr *trace = StackDepotGet(stack_trace_id, &size); 286975772cf55d83f29a24d57d0132d32a22af32f7fKenny Root StackTrace::PrintStack(trace, size, common_flags()->symbolize, 28738c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice common_flags()->strip_path_prefix, 0); 2882ecdfa100af0c18814445608ac7b2bc1e11ef4b2Brian Carlstrom} 289652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root 290652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root// ForEachChunk callback. Aggregates unreachable chunks into a LeakReport. 291f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstromstatic void CollectLeaksCb(uptr chunk, void *arg) { 29208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project CHECK(arg); 293f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom LeakReport *leak_report = reinterpret_cast<LeakReport *>(arg); 294652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root chunk = GetUserBegin(chunk); 295f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom LsanMetadata m(chunk); 296652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root if (!m.allocated()) return; 297652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root if (m.tag() == kDirectlyLeaked || m.tag() == kIndirectlyLeaked) { 29808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project uptr resolution = flags()->resolution; 299652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root if (resolution > 0) { 30008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project uptr size = 0; 301e4b82368b271aa959783814dde0087c84aed53b5Kenny Root const uptr *trace = StackDepotGet(m.stack_trace_id(), &size); 302e4b82368b271aa959783814dde0087c84aed53b5Kenny Root size = Min(size, resolution); 303652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root leak_report->Add(StackDepotPut(trace, size), m.requested_size(), m.tag()); 304652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root } else { 305e4b82368b271aa959783814dde0087c84aed53b5Kenny Root leak_report->Add(m.stack_trace_id(), m.requested_size(), m.tag()); 306652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root } 307e4b82368b271aa959783814dde0087c84aed53b5Kenny Root } 308652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root} 309e4b82368b271aa959783814dde0087c84aed53b5Kenny Root 31008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project// ForEachChunkCallback. Prints addresses of unreachable chunks. 311f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstromstatic void PrintLeakedCb(uptr chunk, void *arg) { 312652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root chunk = GetUserBegin(chunk); 313bad843cfc413e5ccb61bacc426a204def0687e69Kenny Root LsanMetadata m(chunk); 314652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root if (!m.allocated()) return; 315bad843cfc413e5ccb61bacc426a204def0687e69Kenny Root if (m.tag() == kDirectlyLeaked || m.tag() == kIndirectlyLeaked) { 316bad843cfc413e5ccb61bacc426a204def0687e69Kenny Root Printf("%s leaked %zu byte object at %p.\n", 317652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root m.tag() == kDirectlyLeaked ? "Directly" : "Indirectly", 318652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root m.requested_size(), chunk); 319bad843cfc413e5ccb61bacc426a204def0687e69Kenny Root } 320652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root} 321f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom 322652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Rootstatic void PrintMatchedSuppressions() { 32398ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom InternalMmapVector<Suppression *> matched(1); 324f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom suppression_ctx->GetMatched(&matched); 325652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root if (!matched.size()) 32638c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice return; 327f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom const char *line = "-----------------------------------------------------"; 328bc4717526951c5dc5228970cd149bf6bfb5876fbKenny Root Printf("%s\n", line); 329bc4717526951c5dc5228970cd149bf6bfb5876fbKenny Root Printf("Suppressions used:\n"); 330bc4717526951c5dc5228970cd149bf6bfb5876fbKenny Root Printf(" count bytes template\n"); 33138c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice for (uptr i = 0; i < matched.size(); i++) 332bc4717526951c5dc5228970cd149bf6bfb5876fbKenny Root Printf("%7zu %10zu %s\n", static_cast<uptr>(matched[i]->hit_count), 33338c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice matched[i]->weight, matched[i]->templ); 334bc4717526951c5dc5228970cd149bf6bfb5876fbKenny Root Printf("%s\n\n", line); 335bc4717526951c5dc5228970cd149bf6bfb5876fbKenny Root} 33638c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice 3371ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Rootstatic void PrintLeaked() { 338bc4717526951c5dc5228970cd149bf6bfb5876fbKenny Root Printf("\n"); 33938c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice Printf("Reporting individual objects:\n"); 340987b13e30fa7fe65c2b84a47f181a29484cc89dcKenny Root ForEachChunk(PrintLeakedCb, 0 /* arg */); 341bc4717526951c5dc5228970cd149bf6bfb5876fbKenny Root} 34238c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice 3431ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Rootstruct DoLeakCheckParam { 34438c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice bool success; 3451ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root LeakReport leak_report; 34638c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice}; 3471ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root 34838c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dicestatic void DoLeakCheckCallback(const SuspendedThreadsList &suspended_threads, 349f1631ffccd050d5d88da3a26dfe4c2293cf1d762Kenny Root void *arg) { 35038c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice DoLeakCheckParam *param = reinterpret_cast<DoLeakCheckParam *>(arg); 3511ddc76d634923479be2b520b2bf20f71ff4f1f44Kenny Root CHECK(param); 35238c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice CHECK(!param->success); 353ce4ace90d085db0865286fb6819acc82e6c9f64eKenny Root CHECK(param->leak_report.IsEmpty()); 35438c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice ClassifyAllChunks(suspended_threads); 355bc4717526951c5dc5228970cd149bf6bfb5876fbKenny Root ForEachChunk(CollectLeaksCb, ¶m->leak_report); 35698ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom if (!param->leak_report.IsEmpty() && flags()->report_objects) 35798ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom PrintLeaked(); 35898ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom param->success = true; 35998ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom} 36098ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom 36198ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstromvoid DoLeakCheck() { 36298ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom EnsureMainThreadIDIsCorrect(); 36398ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom BlockingMutexLock l(&global_mutex); 3642296bd6bf1d43d1ebceaabbb556d5542d529d311Kenny Root static bool already_done; 3652296bd6bf1d43d1ebceaabbb556d5542d529d311Kenny Root if (already_done) return; 3663a0a06c3fe017c9454dd181555b6904dd88d1002Kenny Root already_done = true; 3673a0a06c3fe017c9454dd181555b6904dd88d1002Kenny Root if (&__lsan_is_turned_off && __lsan_is_turned_off()) 368c6e93518bda6c5bc2959641711eca9d9078fb530Kenny Root return; 369c6e93518bda6c5bc2959641711eca9d9078fb530Kenny Root 3703a0a06c3fe017c9454dd181555b6904dd88d1002Kenny Root DoLeakCheckParam param; 3713a0a06c3fe017c9454dd181555b6904dd88d1002Kenny Root param.success = false; 3723a0a06c3fe017c9454dd181555b6904dd88d1002Kenny Root LockThreadRegistry(); 3733a0a06c3fe017c9454dd181555b6904dd88d1002Kenny Root LockAllocator(); 3746224c2e60c987d560cb5d76aa6af4c185ce87768Brian Carlstrom StopTheWorld(DoLeakCheckCallback, ¶m); 3756224c2e60c987d560cb5d76aa6af4c185ce87768Brian Carlstrom UnlockAllocator(); 3766224c2e60c987d560cb5d76aa6af4c185ce87768Brian Carlstrom UnlockThreadRegistry(); 3776224c2e60c987d560cb5d76aa6af4c185ce87768Brian Carlstrom 3786224c2e60c987d560cb5d76aa6af4c185ce87768Brian Carlstrom if (!param.success) { 3796224c2e60c987d560cb5d76aa6af4c185ce87768Brian Carlstrom Report("LeakSanitizer has encountered a fatal error.\n"); 3806224c2e60c987d560cb5d76aa6af4c185ce87768Brian Carlstrom Die(); 3816224c2e60c987d560cb5d76aa6af4c185ce87768Brian Carlstrom } 3826224c2e60c987d560cb5d76aa6af4c185ce87768Brian Carlstrom uptr have_unsuppressed = param.leak_report.ApplySuppressions(); 3836224c2e60c987d560cb5d76aa6af4c185ce87768Brian Carlstrom if (have_unsuppressed) { 3846224c2e60c987d560cb5d76aa6af4c185ce87768Brian Carlstrom Decorator d; 3852a4faf6763b502c98d13bf79d1c9fba223b698c7Kenny Root Printf("\n" 3862a4faf6763b502c98d13bf79d1c9fba223b698c7Kenny Root "=================================================================" 3872a4faf6763b502c98d13bf79d1c9fba223b698c7Kenny Root "\n"); 3882a4faf6763b502c98d13bf79d1c9fba223b698c7Kenny Root Printf("%s", d.Error()); 3892a4faf6763b502c98d13bf79d1c9fba223b698c7Kenny Root Report("ERROR: LeakSanitizer: detected memory leaks\n"); 3906224c2e60c987d560cb5d76aa6af4c185ce87768Brian Carlstrom Printf("%s", d.End()); 3916224c2e60c987d560cb5d76aa6af4c185ce87768Brian Carlstrom param.leak_report.PrintLargest(flags()->max_leaks); 3926224c2e60c987d560cb5d76aa6af4c185ce87768Brian Carlstrom } 3936224c2e60c987d560cb5d76aa6af4c185ce87768Brian Carlstrom if (have_unsuppressed || (flags()->verbosity >= 1)) { 39432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root PrintMatchedSuppressions(); 39532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root param.leak_report.PrintSummary(); 39632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root } 39732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root if (have_unsuppressed && flags()->exitcode) 39832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root internal__exit(flags()->exitcode); 39932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root} 40032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root 40132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootstatic Suppression *GetSuppressionForAddr(uptr addr) { 40232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root static const uptr kMaxAddrFrames = 16; 40332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root InternalScopedBuffer<AddressInfo> addr_frames(kMaxAddrFrames); 40432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root for (uptr i = 0; i < kMaxAddrFrames; i++) new (&addr_frames[i]) AddressInfo(); 40532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root uptr addr_frames_num = 40632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root getSymbolizer()->SymbolizeCode(addr, addr_frames.data(), kMaxAddrFrames); 40732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root for (uptr i = 0; i < addr_frames_num; i++) { 40832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root Suppression* s; 40932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root if (suppression_ctx->Match(addr_frames[i].function, SuppressionLeak, &s) || 41032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root suppression_ctx->Match(addr_frames[i].file, SuppressionLeak, &s) || 41132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root suppression_ctx->Match(addr_frames[i].module, SuppressionLeak, &s)) 41232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root return s; 41332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root } 41432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root return 0; 41532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root} 41632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root 41732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootstatic Suppression *GetSuppressionForStack(u32 stack_trace_id) { 41832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root uptr size = 0; 41932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root const uptr *trace = StackDepotGet(stack_trace_id, &size); 420e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root for (uptr i = 0; i < size; i++) { 421e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root Suppression *s = 42232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root GetSuppressionForAddr(StackTrace::GetPreviousInstructionPc(trace[i])); 42332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root if (s) return s; 42432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root } 42532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root return 0; 42632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root} 42732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root 42832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root///// LeakReport implementation. ///// 429f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root 430f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root// A hard limit on the number of distinct leaks, to avoid quadratic complexity 431f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root// in LeakReport::Add(). We don't expect to ever see this many leaks in 432f0bb425ede548a3771bb69273eb85ad7fdde1befKenny Root// real-world applications. 43332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root// FIXME: Get rid of this limit by changing the implementation of LeakReport to 43432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root// use a hash table. 43532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootconst uptr kMaxLeaksConsidered = 5000; 43632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root 43732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootvoid LeakReport::Add(u32 stack_trace_id, uptr leaked_size, ChunkTag tag) { 43832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root CHECK(tag == kDirectlyLeaked || tag == kIndirectlyLeaked); 43932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root bool is_directly_leaked = (tag == kDirectlyLeaked); 44032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root for (uptr i = 0; i < leaks_.size(); i++) 44132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root if (leaks_[i].stack_trace_id == stack_trace_id && 44232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root leaks_[i].is_directly_leaked == is_directly_leaked) { 44332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root leaks_[i].hit_count++; 44432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root leaks_[i].total_size += leaked_size; 44532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root return; 44632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root } 44732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root if (leaks_.size() == kMaxLeaksConsidered) return; 44832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root Leak leak = { /* hit_count */ 1, leaked_size, stack_trace_id, 44932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root is_directly_leaked, /* is_suppressed */ false }; 45032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root leaks_.push_back(leak); 45132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root} 45232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root 45332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootstatic bool LeakComparator(const Leak &leak1, const Leak &leak2) { 45432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root if (leak1.is_directly_leaked == leak2.is_directly_leaked) 45532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root return leak1.total_size > leak2.total_size; 45632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root else 45732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root return leak1.is_directly_leaked; 45832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root} 45932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root 46032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootvoid LeakReport::PrintLargest(uptr num_leaks_to_print) { 46136e383e2f9c447e05adcca4426d8b33b2ef73ca7Kenny Root CHECK(leaks_.size() <= kMaxLeaksConsidered); 46236e383e2f9c447e05adcca4426d8b33b2ef73ca7Kenny Root Printf("\n"); 46332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root if (leaks_.size() == kMaxLeaksConsidered) 46432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root Printf("Too many leaks! Only the first %zu leaks encountered will be " 46532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root "reported.\n", 46632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root kMaxLeaksConsidered); 46732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root 46832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root uptr unsuppressed_count = 0; 46932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root for (uptr i = 0; i < leaks_.size(); i++) 47032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root if (!leaks_[i].is_suppressed) unsuppressed_count++; 47132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root if (num_leaks_to_print > 0 && num_leaks_to_print < unsuppressed_count) 47232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root Printf("The %zu largest leak(s):\n", num_leaks_to_print); 47332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root InternalSort(&leaks_, leaks_.size(), LeakComparator); 47432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root uptr leaks_printed = 0; 47532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root Decorator d; 47632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root for (uptr i = 0; i < leaks_.size(); i++) { 47732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root if (leaks_[i].is_suppressed) continue; 4787c3263f16bae0f1b2125de2c3c1c683303e768ceKenny Root Printf("%s", d.Leak()); 47932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root Printf("%s leak of %zu byte(s) in %zu object(s) allocated from:\n", 48032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root leaks_[i].is_directly_leaked ? "Direct" : "Indirect", 48132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root leaks_[i].total_size, leaks_[i].hit_count); 48232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root Printf("%s", d.End()); 48332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root PrintStackTraceById(leaks_[i].stack_trace_id); 48432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root Printf("\n"); 48532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root leaks_printed++; 48635beb3047b2b8ffc019f8218989a0255cc5e3818Kenny Root if (leaks_printed == num_leaks_to_print) break; 48735beb3047b2b8ffc019f8218989a0255cc5e3818Kenny Root } 48832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root if (leaks_printed < unsuppressed_count) { 48932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root uptr remaining = unsuppressed_count - leaks_printed; 4909ec4f876b0b8e2b659728d0468492cde3763ad5dKenny Root Printf("Omitting %zu more leak(s).\n", remaining); 4919ec4f876b0b8e2b659728d0468492cde3763ad5dKenny Root } 49232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root} 49332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root 49432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootvoid LeakReport::PrintSummary() { 49532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root CHECK(leaks_.size() <= kMaxLeaksConsidered); 49632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root uptr bytes = 0, allocations = 0; 49732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root for (uptr i = 0; i < leaks_.size(); i++) { 49832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root if (leaks_[i].is_suppressed) continue; 49932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root bytes += leaks_[i].total_size; 50032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root allocations += leaks_[i].hit_count; 50132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root } 50232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root const int kMaxSummaryLength = 128; 50332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root InternalScopedBuffer<char> summary(kMaxSummaryLength); 50432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root internal_snprintf(summary.data(), kMaxSummaryLength, 50532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root "LeakSanitizer: %zu byte(s) leaked in %zu allocation(s).", 506e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root bytes, allocations); 507e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root __sanitizer_report_error_summary(summary.data()); 508e1429740ee37db9422d7622d11d32a29a4bc4301Kenny Root} 50932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root 51032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootuptr LeakReport::ApplySuppressions() { 51132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root uptr unsuppressed_count = 0; 51232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root for (uptr i = 0; i < leaks_.size(); i++) { 51332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root Suppression *s = GetSuppressionForStack(leaks_[i].stack_trace_id); 51432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root if (s) { 51532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root s->weight += leaks_[i].total_size; 51632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root s->hit_count += leaks_[i].hit_count; 51732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root leaks_[i].is_suppressed = true; 51832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root } else { 51932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root unsuppressed_count++; 52032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root } 52132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root } 52232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root return unsuppressed_count; 52332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root} 52432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root} // namespace __lsan 52532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root#endif // CAN_SANITIZE_LEAKS 52632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root 52732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootusing namespace __lsan; // NOLINT 52832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root 52932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootextern "C" { 53032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny RootSANITIZER_INTERFACE_ATTRIBUTE 53132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootvoid __lsan_ignore_object(const void *p) { 53232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root#if CAN_SANITIZE_LEAKS 53332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root // Cannot use PointsIntoChunk or LsanMetadata here, since the allocator is not 53432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root // locked. 53532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root BlockingMutexLock l(&global_mutex); 53632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root IgnoreObjectResult res = IgnoreObjectLocked(p); 53732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root if (res == kIgnoreObjectInvalid && flags()->verbosity >= 2) 53832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root Report("__lsan_ignore_object(): no heap object found at %p", p); 53932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root if (res == kIgnoreObjectAlreadyIgnored && flags()->verbosity >= 2) 54032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root Report("__lsan_ignore_object(): " 54132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root "heap object at %p is already being ignored\n", p); 54232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root if (res == kIgnoreObjectSuccess && flags()->verbosity >= 3) 54332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root Report("__lsan_ignore_object(): ignoring heap object at %p\n", p); 54432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root#endif // CAN_SANITIZE_LEAKS 54532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root} 54632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root 54732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny RootSANITIZER_INTERFACE_ATTRIBUTE 54832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootvoid __lsan_disable() { 54932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root#if CAN_SANITIZE_LEAKS 55032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root __lsan::disable_counter++; 55132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root#endif 55232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root} 55332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root 55432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny RootSANITIZER_INTERFACE_ATTRIBUTE 55532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootvoid __lsan_enable() { 55632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root#if CAN_SANITIZE_LEAKS 55732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root if (!__lsan::disable_counter) { 55832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root Report("Unmatched call to __lsan_enable().\n"); 55932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root Die(); 56032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root } 56132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root __lsan::disable_counter--; 56232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root#endif 56332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root} 56432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root 56532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny RootSANITIZER_INTERFACE_ATTRIBUTE 56632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootvoid __lsan_do_leak_check() { 56732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root#if CAN_SANITIZE_LEAKS 56832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root if (common_flags()->detect_leaks) 56932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root __lsan::DoLeakCheck(); 57032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root#endif // CAN_SANITIZE_LEAKS 57132850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root} 57232850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root 57332850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root#if !SANITIZER_SUPPORTS_WEAK_HOOKS 57432850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny RootSANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE 57532850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Rootint __lsan_is_turned_off() { 57632850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root return 0; 57732850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root} 57832850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root#endif 57932850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root} // extern "C" 58032850b6ce29c70150cfe01c4ce2a1b353d92e6feKenny Root