lsan_common.cpp revision 1.3 1 1.1 mrg //=-- lsan_common.cpp -----------------------------------------------------===//
2 1.1 mrg //
3 1.1 mrg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 1.1 mrg // See https://llvm.org/LICENSE.txt for license information.
5 1.1 mrg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 1.1 mrg //
7 1.1 mrg //===----------------------------------------------------------------------===//
8 1.1 mrg //
9 1.1 mrg // This file is a part of LeakSanitizer.
10 1.1 mrg // Implementation of common leak checking functionality.
11 1.1 mrg //
12 1.1 mrg //===----------------------------------------------------------------------===//
13 1.1 mrg
14 1.1 mrg #include "lsan_common.h"
15 1.1 mrg
16 1.1 mrg #include "sanitizer_common/sanitizer_common.h"
17 1.1 mrg #include "sanitizer_common/sanitizer_flag_parser.h"
18 1.1 mrg #include "sanitizer_common/sanitizer_flags.h"
19 1.1 mrg #include "sanitizer_common/sanitizer_placement_new.h"
20 1.1 mrg #include "sanitizer_common/sanitizer_procmaps.h"
21 1.1 mrg #include "sanitizer_common/sanitizer_report_decorator.h"
22 1.1 mrg #include "sanitizer_common/sanitizer_stackdepot.h"
23 1.1 mrg #include "sanitizer_common/sanitizer_stacktrace.h"
24 1.1 mrg #include "sanitizer_common/sanitizer_suppressions.h"
25 1.1 mrg #include "sanitizer_common/sanitizer_thread_registry.h"
26 1.1 mrg #include "sanitizer_common/sanitizer_tls_get_addr.h"
27 1.1 mrg
28 1.1 mrg #if CAN_SANITIZE_LEAKS
29 1.1 mrg namespace __lsan {
30 1.1 mrg
31 1.1 mrg // This mutex is used to prevent races between DoLeakCheck and IgnoreObject, and
32 1.1 mrg // also to protect the global list of root regions.
33 1.3 mrg Mutex global_mutex;
34 1.1 mrg
35 1.1 mrg Flags lsan_flags;
36 1.1 mrg
37 1.3 mrg
38 1.1 mrg void DisableCounterUnderflow() {
39 1.1 mrg if (common_flags()->detect_leaks) {
40 1.1 mrg Report("Unmatched call to __lsan_enable().\n");
41 1.1 mrg Die();
42 1.1 mrg }
43 1.1 mrg }
44 1.1 mrg
45 1.1 mrg void Flags::SetDefaults() {
46 1.1 mrg #define LSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
47 1.1 mrg #include "lsan_flags.inc"
48 1.1 mrg #undef LSAN_FLAG
49 1.1 mrg }
50 1.1 mrg
51 1.1 mrg void RegisterLsanFlags(FlagParser *parser, Flags *f) {
52 1.1 mrg #define LSAN_FLAG(Type, Name, DefaultValue, Description) \
53 1.1 mrg RegisterFlag(parser, #Name, Description, &f->Name);
54 1.1 mrg #include "lsan_flags.inc"
55 1.1 mrg #undef LSAN_FLAG
56 1.1 mrg }
57 1.1 mrg
58 1.1 mrg #define LOG_POINTERS(...) \
59 1.1 mrg do { \
60 1.1 mrg if (flags()->log_pointers) Report(__VA_ARGS__); \
61 1.1 mrg } while (0)
62 1.1 mrg
63 1.1 mrg #define LOG_THREADS(...) \
64 1.1 mrg do { \
65 1.1 mrg if (flags()->log_threads) Report(__VA_ARGS__); \
66 1.1 mrg } while (0)
67 1.1 mrg
68 1.3 mrg class LeakSuppressionContext {
69 1.3 mrg bool parsed = false;
70 1.3 mrg SuppressionContext context;
71 1.3 mrg bool suppressed_stacks_sorted = true;
72 1.3 mrg InternalMmapVector<u32> suppressed_stacks;
73 1.3 mrg
74 1.3 mrg Suppression *GetSuppressionForAddr(uptr addr);
75 1.3 mrg void LazyInit();
76 1.3 mrg
77 1.3 mrg public:
78 1.3 mrg LeakSuppressionContext(const char *supprression_types[],
79 1.3 mrg int suppression_types_num)
80 1.3 mrg : context(supprression_types, suppression_types_num) {}
81 1.3 mrg
82 1.3 mrg Suppression *GetSuppressionForStack(u32 stack_trace_id,
83 1.3 mrg const StackTrace &stack);
84 1.3 mrg
85 1.3 mrg const InternalMmapVector<u32> &GetSortedSuppressedStacks() {
86 1.3 mrg if (!suppressed_stacks_sorted) {
87 1.3 mrg suppressed_stacks_sorted = true;
88 1.3 mrg SortAndDedup(suppressed_stacks);
89 1.3 mrg }
90 1.3 mrg return suppressed_stacks;
91 1.3 mrg }
92 1.3 mrg void PrintMatchedSuppressions();
93 1.3 mrg };
94 1.3 mrg
95 1.3 mrg ALIGNED(64) static char suppression_placeholder[sizeof(LeakSuppressionContext)];
96 1.3 mrg static LeakSuppressionContext *suppression_ctx = nullptr;
97 1.1 mrg static const char kSuppressionLeak[] = "leak";
98 1.1 mrg static const char *kSuppressionTypes[] = { kSuppressionLeak };
99 1.1 mrg static const char kStdSuppressions[] =
100 1.1 mrg #if SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT
101 1.3 mrg // For more details refer to the SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT
102 1.3 mrg // definition.
103 1.3 mrg "leak:*pthread_exit*\n"
104 1.1 mrg #endif // SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT
105 1.1 mrg #if SANITIZER_MAC
106 1.3 mrg // For Darwin and os_log/os_trace: https://reviews.llvm.org/D35173
107 1.3 mrg "leak:*_os_trace*\n"
108 1.1 mrg #endif
109 1.3 mrg // TLS leak in some glibc versions, described in
110 1.3 mrg // https://sourceware.org/bugzilla/show_bug.cgi?id=12650.
111 1.3 mrg "leak:*tls_get_addr*\n";
112 1.1 mrg
113 1.1 mrg void InitializeSuppressions() {
114 1.1 mrg CHECK_EQ(nullptr, suppression_ctx);
115 1.1 mrg suppression_ctx = new (suppression_placeholder)
116 1.3 mrg LeakSuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
117 1.1 mrg }
118 1.1 mrg
119 1.3 mrg void LeakSuppressionContext::LazyInit() {
120 1.3 mrg if (!parsed) {
121 1.3 mrg parsed = true;
122 1.3 mrg context.ParseFromFile(flags()->suppressions);
123 1.3 mrg if (&__lsan_default_suppressions)
124 1.3 mrg context.Parse(__lsan_default_suppressions());
125 1.3 mrg context.Parse(kStdSuppressions);
126 1.3 mrg }
127 1.3 mrg }
128 1.3 mrg
129 1.3 mrg static LeakSuppressionContext *GetSuppressionContext() {
130 1.1 mrg CHECK(suppression_ctx);
131 1.1 mrg return suppression_ctx;
132 1.1 mrg }
133 1.1 mrg
134 1.3 mrg static InternalMmapVectorNoCtor<RootRegion> root_regions;
135 1.1 mrg
136 1.3 mrg InternalMmapVectorNoCtor<RootRegion> const *GetRootRegions() {
137 1.3 mrg return &root_regions;
138 1.1 mrg }
139 1.1 mrg
140 1.1 mrg void InitCommonLsan() {
141 1.1 mrg if (common_flags()->detect_leaks) {
142 1.1 mrg // Initialization which can fail or print warnings should only be done if
143 1.1 mrg // LSan is actually enabled.
144 1.1 mrg InitializeSuppressions();
145 1.1 mrg InitializePlatformSpecificModules();
146 1.1 mrg }
147 1.1 mrg }
148 1.1 mrg
149 1.1 mrg class Decorator: public __sanitizer::SanitizerCommonDecorator {
150 1.1 mrg public:
151 1.1 mrg Decorator() : SanitizerCommonDecorator() { }
152 1.1 mrg const char *Error() { return Red(); }
153 1.1 mrg const char *Leak() { return Blue(); }
154 1.1 mrg };
155 1.1 mrg
156 1.1 mrg static inline bool CanBeAHeapPointer(uptr p) {
157 1.1 mrg // Since our heap is located in mmap-ed memory, we can assume a sensible lower
158 1.1 mrg // bound on heap addresses.
159 1.1 mrg const uptr kMinAddress = 4 * 4096;
160 1.1 mrg if (p < kMinAddress) return false;
161 1.1 mrg #if defined(__x86_64__)
162 1.1 mrg // Accept only canonical form user-space addresses.
163 1.1 mrg return ((p >> 47) == 0);
164 1.1 mrg #elif defined(__mips64)
165 1.1 mrg return ((p >> 40) == 0);
166 1.1 mrg #elif defined(__aarch64__)
167 1.1 mrg unsigned runtimeVMA =
168 1.1 mrg (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1);
169 1.1 mrg return ((p >> runtimeVMA) == 0);
170 1.1 mrg #else
171 1.1 mrg return true;
172 1.1 mrg #endif
173 1.1 mrg }
174 1.1 mrg
175 1.1 mrg // Scans the memory range, looking for byte patterns that point into allocator
176 1.1 mrg // chunks. Marks those chunks with |tag| and adds them to |frontier|.
177 1.1 mrg // There are two usage modes for this function: finding reachable chunks
178 1.1 mrg // (|tag| = kReachable) and finding indirectly leaked chunks
179 1.1 mrg // (|tag| = kIndirectlyLeaked). In the second case, there's no flood fill,
180 1.1 mrg // so |frontier| = 0.
181 1.1 mrg void ScanRangeForPointers(uptr begin, uptr end,
182 1.1 mrg Frontier *frontier,
183 1.1 mrg const char *region_type, ChunkTag tag) {
184 1.1 mrg CHECK(tag == kReachable || tag == kIndirectlyLeaked);
185 1.1 mrg const uptr alignment = flags()->pointer_alignment();
186 1.3 mrg LOG_POINTERS("Scanning %s range %p-%p.\n", region_type, (void *)begin,
187 1.3 mrg (void *)end);
188 1.1 mrg uptr pp = begin;
189 1.1 mrg if (pp % alignment)
190 1.1 mrg pp = pp + alignment - pp % alignment;
191 1.1 mrg for (; pp + sizeof(void *) <= end; pp += alignment) {
192 1.1 mrg void *p = *reinterpret_cast<void **>(pp);
193 1.1 mrg if (!CanBeAHeapPointer(reinterpret_cast<uptr>(p))) continue;
194 1.1 mrg uptr chunk = PointsIntoChunk(p);
195 1.1 mrg if (!chunk) continue;
196 1.1 mrg // Pointers to self don't count. This matters when tag == kIndirectlyLeaked.
197 1.1 mrg if (chunk == begin) continue;
198 1.1 mrg LsanMetadata m(chunk);
199 1.1 mrg if (m.tag() == kReachable || m.tag() == kIgnored) continue;
200 1.1 mrg
201 1.1 mrg // Do this check relatively late so we can log only the interesting cases.
202 1.1 mrg if (!flags()->use_poisoned && WordIsPoisoned(pp)) {
203 1.1 mrg LOG_POINTERS(
204 1.1 mrg "%p is poisoned: ignoring %p pointing into chunk %p-%p of size "
205 1.1 mrg "%zu.\n",
206 1.3 mrg (void *)pp, p, (void *)chunk, (void *)(chunk + m.requested_size()),
207 1.3 mrg m.requested_size());
208 1.1 mrg continue;
209 1.1 mrg }
210 1.1 mrg
211 1.1 mrg m.set_tag(tag);
212 1.3 mrg LOG_POINTERS("%p: found %p pointing into chunk %p-%p of size %zu.\n",
213 1.3 mrg (void *)pp, p, (void *)chunk,
214 1.3 mrg (void *)(chunk + m.requested_size()), m.requested_size());
215 1.1 mrg if (frontier)
216 1.1 mrg frontier->push_back(chunk);
217 1.1 mrg }
218 1.1 mrg }
219 1.1 mrg
220 1.1 mrg // Scans a global range for pointers
221 1.1 mrg void ScanGlobalRange(uptr begin, uptr end, Frontier *frontier) {
222 1.1 mrg uptr allocator_begin = 0, allocator_end = 0;
223 1.1 mrg GetAllocatorGlobalRange(&allocator_begin, &allocator_end);
224 1.1 mrg if (begin <= allocator_begin && allocator_begin < end) {
225 1.1 mrg CHECK_LE(allocator_begin, allocator_end);
226 1.1 mrg CHECK_LE(allocator_end, end);
227 1.1 mrg if (begin < allocator_begin)
228 1.1 mrg ScanRangeForPointers(begin, allocator_begin, frontier, "GLOBAL",
229 1.1 mrg kReachable);
230 1.1 mrg if (allocator_end < end)
231 1.1 mrg ScanRangeForPointers(allocator_end, end, frontier, "GLOBAL", kReachable);
232 1.1 mrg } else {
233 1.1 mrg ScanRangeForPointers(begin, end, frontier, "GLOBAL", kReachable);
234 1.1 mrg }
235 1.1 mrg }
236 1.1 mrg
237 1.1 mrg void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg) {
238 1.1 mrg Frontier *frontier = reinterpret_cast<Frontier *>(arg);
239 1.1 mrg ScanRangeForPointers(begin, end, frontier, "FAKE STACK", kReachable);
240 1.1 mrg }
241 1.1 mrg
242 1.3 mrg #if SANITIZER_FUCHSIA
243 1.3 mrg
244 1.3 mrg // Fuchsia handles all threads together with its own callback.
245 1.3 mrg static void ProcessThreads(SuspendedThreadsList const &, Frontier *) {}
246 1.3 mrg
247 1.3 mrg #else
248 1.3 mrg
249 1.3 mrg #if SANITIZER_ANDROID
250 1.3 mrg // FIXME: Move this out into *libcdep.cpp
251 1.3 mrg extern "C" SANITIZER_WEAK_ATTRIBUTE void __libc_iterate_dynamic_tls(
252 1.3 mrg pid_t, void (*cb)(void *, void *, uptr, void *), void *);
253 1.3 mrg #endif
254 1.3 mrg
255 1.3 mrg static void ProcessThreadRegistry(Frontier *frontier) {
256 1.3 mrg InternalMmapVector<uptr> ptrs;
257 1.3 mrg GetThreadRegistryLocked()->RunCallbackForEachThreadLocked(
258 1.3 mrg GetAdditionalThreadContextPtrs, &ptrs);
259 1.3 mrg
260 1.3 mrg for (uptr i = 0; i < ptrs.size(); ++i) {
261 1.3 mrg void *ptr = reinterpret_cast<void *>(ptrs[i]);
262 1.3 mrg uptr chunk = PointsIntoChunk(ptr);
263 1.3 mrg if (!chunk)
264 1.3 mrg continue;
265 1.3 mrg LsanMetadata m(chunk);
266 1.3 mrg if (!m.allocated())
267 1.3 mrg continue;
268 1.3 mrg
269 1.3 mrg // Mark as reachable and add to frontier.
270 1.3 mrg LOG_POINTERS("Treating pointer %p from ThreadContext as reachable\n", ptr);
271 1.3 mrg m.set_tag(kReachable);
272 1.3 mrg frontier->push_back(chunk);
273 1.3 mrg }
274 1.3 mrg }
275 1.3 mrg
276 1.1 mrg // Scans thread data (stacks and TLS) for heap pointers.
277 1.1 mrg static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
278 1.1 mrg Frontier *frontier) {
279 1.3 mrg InternalMmapVector<uptr> registers;
280 1.1 mrg for (uptr i = 0; i < suspended_threads.ThreadCount(); i++) {
281 1.1 mrg tid_t os_id = static_cast<tid_t>(suspended_threads.GetThreadID(i));
282 1.3 mrg LOG_THREADS("Processing thread %llu.\n", os_id);
283 1.1 mrg uptr stack_begin, stack_end, tls_begin, tls_end, cache_begin, cache_end;
284 1.1 mrg DTLS *dtls;
285 1.1 mrg bool thread_found = GetThreadRangesLocked(os_id, &stack_begin, &stack_end,
286 1.1 mrg &tls_begin, &tls_end,
287 1.1 mrg &cache_begin, &cache_end, &dtls);
288 1.1 mrg if (!thread_found) {
289 1.1 mrg // If a thread can't be found in the thread registry, it's probably in the
290 1.1 mrg // process of destruction. Log this event and move on.
291 1.3 mrg LOG_THREADS("Thread %llu not found in registry.\n", os_id);
292 1.1 mrg continue;
293 1.1 mrg }
294 1.1 mrg uptr sp;
295 1.1 mrg PtraceRegistersStatus have_registers =
296 1.3 mrg suspended_threads.GetRegistersAndSP(i, ®isters, &sp);
297 1.1 mrg if (have_registers != REGISTERS_AVAILABLE) {
298 1.3 mrg Report("Unable to get registers from thread %llu.\n", os_id);
299 1.1 mrg // If unable to get SP, consider the entire stack to be reachable unless
300 1.1 mrg // GetRegistersAndSP failed with ESRCH.
301 1.1 mrg if (have_registers == REGISTERS_UNAVAILABLE_FATAL) continue;
302 1.1 mrg sp = stack_begin;
303 1.1 mrg }
304 1.1 mrg
305 1.3 mrg if (flags()->use_registers && have_registers) {
306 1.3 mrg uptr registers_begin = reinterpret_cast<uptr>(registers.data());
307 1.3 mrg uptr registers_end =
308 1.3 mrg reinterpret_cast<uptr>(registers.data() + registers.size());
309 1.1 mrg ScanRangeForPointers(registers_begin, registers_end, frontier,
310 1.1 mrg "REGISTERS", kReachable);
311 1.3 mrg }
312 1.1 mrg
313 1.1 mrg if (flags()->use_stacks) {
314 1.3 mrg LOG_THREADS("Stack at %p-%p (SP = %p).\n", (void *)stack_begin,
315 1.3 mrg (void *)stack_end, (void *)sp);
316 1.1 mrg if (sp < stack_begin || sp >= stack_end) {
317 1.1 mrg // SP is outside the recorded stack range (e.g. the thread is running a
318 1.1 mrg // signal handler on alternate stack, or swapcontext was used).
319 1.1 mrg // Again, consider the entire stack range to be reachable.
320 1.1 mrg LOG_THREADS("WARNING: stack pointer not in stack range.\n");
321 1.1 mrg uptr page_size = GetPageSizeCached();
322 1.1 mrg int skipped = 0;
323 1.1 mrg while (stack_begin < stack_end &&
324 1.1 mrg !IsAccessibleMemoryRange(stack_begin, 1)) {
325 1.1 mrg skipped++;
326 1.1 mrg stack_begin += page_size;
327 1.1 mrg }
328 1.1 mrg LOG_THREADS("Skipped %d guard page(s) to obtain stack %p-%p.\n",
329 1.3 mrg skipped, (void *)stack_begin, (void *)stack_end);
330 1.1 mrg } else {
331 1.1 mrg // Shrink the stack range to ignore out-of-scope values.
332 1.1 mrg stack_begin = sp;
333 1.1 mrg }
334 1.1 mrg ScanRangeForPointers(stack_begin, stack_end, frontier, "STACK",
335 1.1 mrg kReachable);
336 1.1 mrg ForEachExtraStackRange(os_id, ForEachExtraStackRangeCb, frontier);
337 1.1 mrg }
338 1.1 mrg
339 1.1 mrg if (flags()->use_tls) {
340 1.1 mrg if (tls_begin) {
341 1.3 mrg LOG_THREADS("TLS at %p-%p.\n", (void *)tls_begin, (void *)tls_end);
342 1.1 mrg // If the tls and cache ranges don't overlap, scan full tls range,
343 1.1 mrg // otherwise, only scan the non-overlapping portions
344 1.1 mrg if (cache_begin == cache_end || tls_end < cache_begin ||
345 1.1 mrg tls_begin > cache_end) {
346 1.1 mrg ScanRangeForPointers(tls_begin, tls_end, frontier, "TLS", kReachable);
347 1.1 mrg } else {
348 1.1 mrg if (tls_begin < cache_begin)
349 1.1 mrg ScanRangeForPointers(tls_begin, cache_begin, frontier, "TLS",
350 1.1 mrg kReachable);
351 1.1 mrg if (tls_end > cache_end)
352 1.1 mrg ScanRangeForPointers(cache_end, tls_end, frontier, "TLS",
353 1.1 mrg kReachable);
354 1.1 mrg }
355 1.1 mrg }
356 1.3 mrg #if SANITIZER_ANDROID
357 1.3 mrg auto *cb = +[](void *dtls_begin, void *dtls_end, uptr /*dso_idd*/,
358 1.3 mrg void *arg) -> void {
359 1.3 mrg ScanRangeForPointers(reinterpret_cast<uptr>(dtls_begin),
360 1.3 mrg reinterpret_cast<uptr>(dtls_end),
361 1.3 mrg reinterpret_cast<Frontier *>(arg), "DTLS",
362 1.3 mrg kReachable);
363 1.3 mrg };
364 1.3 mrg
365 1.3 mrg // FIXME: There might be a race-condition here (and in Bionic) if the
366 1.3 mrg // thread is suspended in the middle of updating its DTLS. IOWs, we
367 1.3 mrg // could scan already freed memory. (probably fine for now)
368 1.3 mrg __libc_iterate_dynamic_tls(os_id, cb, frontier);
369 1.3 mrg #else
370 1.1 mrg if (dtls && !DTLSInDestruction(dtls)) {
371 1.3 mrg ForEachDVT(dtls, [&](const DTLS::DTV &dtv, int id) {
372 1.3 mrg uptr dtls_beg = dtv.beg;
373 1.3 mrg uptr dtls_end = dtls_beg + dtv.size;
374 1.1 mrg if (dtls_beg < dtls_end) {
375 1.3 mrg LOG_THREADS("DTLS %d at %p-%p.\n", id, (void *)dtls_beg,
376 1.3 mrg (void *)dtls_end);
377 1.1 mrg ScanRangeForPointers(dtls_beg, dtls_end, frontier, "DTLS",
378 1.1 mrg kReachable);
379 1.1 mrg }
380 1.3 mrg });
381 1.1 mrg } else {
382 1.1 mrg // We are handling a thread with DTLS under destruction. Log about
383 1.1 mrg // this and continue.
384 1.3 mrg LOG_THREADS("Thread %llu has DTLS under destruction.\n", os_id);
385 1.1 mrg }
386 1.3 mrg #endif
387 1.1 mrg }
388 1.1 mrg }
389 1.3 mrg
390 1.3 mrg // Add pointers reachable from ThreadContexts
391 1.3 mrg ProcessThreadRegistry(frontier);
392 1.1 mrg }
393 1.1 mrg
394 1.3 mrg #endif // SANITIZER_FUCHSIA
395 1.3 mrg
396 1.1 mrg void ScanRootRegion(Frontier *frontier, const RootRegion &root_region,
397 1.1 mrg uptr region_begin, uptr region_end, bool is_readable) {
398 1.1 mrg uptr intersection_begin = Max(root_region.begin, region_begin);
399 1.1 mrg uptr intersection_end = Min(region_end, root_region.begin + root_region.size);
400 1.1 mrg if (intersection_begin >= intersection_end) return;
401 1.1 mrg LOG_POINTERS("Root region %p-%p intersects with mapped region %p-%p (%s)\n",
402 1.3 mrg (void *)root_region.begin,
403 1.3 mrg (void *)(root_region.begin + root_region.size),
404 1.3 mrg (void *)region_begin, (void *)region_end,
405 1.1 mrg is_readable ? "readable" : "unreadable");
406 1.1 mrg if (is_readable)
407 1.1 mrg ScanRangeForPointers(intersection_begin, intersection_end, frontier, "ROOT",
408 1.1 mrg kReachable);
409 1.1 mrg }
410 1.1 mrg
411 1.1 mrg static void ProcessRootRegion(Frontier *frontier,
412 1.1 mrg const RootRegion &root_region) {
413 1.1 mrg MemoryMappingLayout proc_maps(/*cache_enabled*/ true);
414 1.1 mrg MemoryMappedSegment segment;
415 1.1 mrg while (proc_maps.Next(&segment)) {
416 1.1 mrg ScanRootRegion(frontier, root_region, segment.start, segment.end,
417 1.1 mrg segment.IsReadable());
418 1.1 mrg }
419 1.1 mrg }
420 1.1 mrg
421 1.1 mrg // Scans root regions for heap pointers.
422 1.1 mrg static void ProcessRootRegions(Frontier *frontier) {
423 1.1 mrg if (!flags()->use_root_regions) return;
424 1.3 mrg for (uptr i = 0; i < root_regions.size(); i++)
425 1.3 mrg ProcessRootRegion(frontier, root_regions[i]);
426 1.1 mrg }
427 1.1 mrg
428 1.1 mrg static void FloodFillTag(Frontier *frontier, ChunkTag tag) {
429 1.1 mrg while (frontier->size()) {
430 1.1 mrg uptr next_chunk = frontier->back();
431 1.1 mrg frontier->pop_back();
432 1.1 mrg LsanMetadata m(next_chunk);
433 1.1 mrg ScanRangeForPointers(next_chunk, next_chunk + m.requested_size(), frontier,
434 1.1 mrg "HEAP", tag);
435 1.1 mrg }
436 1.1 mrg }
437 1.1 mrg
438 1.1 mrg // ForEachChunk callback. If the chunk is marked as leaked, marks all chunks
439 1.1 mrg // which are reachable from it as indirectly leaked.
440 1.1 mrg static void MarkIndirectlyLeakedCb(uptr chunk, void *arg) {
441 1.1 mrg chunk = GetUserBegin(chunk);
442 1.1 mrg LsanMetadata m(chunk);
443 1.1 mrg if (m.allocated() && m.tag() != kReachable) {
444 1.1 mrg ScanRangeForPointers(chunk, chunk + m.requested_size(),
445 1.1 mrg /* frontier */ nullptr, "HEAP", kIndirectlyLeaked);
446 1.1 mrg }
447 1.1 mrg }
448 1.1 mrg
449 1.3 mrg static void IgnoredSuppressedCb(uptr chunk, void *arg) {
450 1.3 mrg CHECK(arg);
451 1.3 mrg chunk = GetUserBegin(chunk);
452 1.3 mrg LsanMetadata m(chunk);
453 1.3 mrg if (!m.allocated() || m.tag() == kIgnored)
454 1.3 mrg return;
455 1.3 mrg
456 1.3 mrg const InternalMmapVector<u32> &suppressed =
457 1.3 mrg *static_cast<const InternalMmapVector<u32> *>(arg);
458 1.3 mrg uptr idx = InternalLowerBound(suppressed, m.stack_trace_id());
459 1.3 mrg if (idx >= suppressed.size() || m.stack_trace_id() != suppressed[idx])
460 1.3 mrg return;
461 1.3 mrg
462 1.3 mrg LOG_POINTERS("Suppressed: chunk %p-%p of size %zu.\n", (void *)chunk,
463 1.3 mrg (void *)(chunk + m.requested_size()), m.requested_size());
464 1.3 mrg m.set_tag(kIgnored);
465 1.3 mrg }
466 1.3 mrg
467 1.1 mrg // ForEachChunk callback. If chunk is marked as ignored, adds its address to
468 1.1 mrg // frontier.
469 1.1 mrg static void CollectIgnoredCb(uptr chunk, void *arg) {
470 1.1 mrg CHECK(arg);
471 1.1 mrg chunk = GetUserBegin(chunk);
472 1.1 mrg LsanMetadata m(chunk);
473 1.1 mrg if (m.allocated() && m.tag() == kIgnored) {
474 1.3 mrg LOG_POINTERS("Ignored: chunk %p-%p of size %zu.\n", (void *)chunk,
475 1.3 mrg (void *)(chunk + m.requested_size()), m.requested_size());
476 1.1 mrg reinterpret_cast<Frontier *>(arg)->push_back(chunk);
477 1.1 mrg }
478 1.1 mrg }
479 1.1 mrg
480 1.3 mrg static uptr GetCallerPC(const StackTrace &stack) {
481 1.1 mrg // The top frame is our malloc/calloc/etc. The next frame is the caller.
482 1.1 mrg if (stack.size >= 2)
483 1.1 mrg return stack.trace[1];
484 1.1 mrg return 0;
485 1.1 mrg }
486 1.1 mrg
487 1.1 mrg struct InvalidPCParam {
488 1.1 mrg Frontier *frontier;
489 1.1 mrg bool skip_linker_allocations;
490 1.1 mrg };
491 1.1 mrg
492 1.1 mrg // ForEachChunk callback. If the caller pc is invalid or is within the linker,
493 1.1 mrg // mark as reachable. Called by ProcessPlatformSpecificAllocations.
494 1.1 mrg static void MarkInvalidPCCb(uptr chunk, void *arg) {
495 1.1 mrg CHECK(arg);
496 1.1 mrg InvalidPCParam *param = reinterpret_cast<InvalidPCParam *>(arg);
497 1.1 mrg chunk = GetUserBegin(chunk);
498 1.1 mrg LsanMetadata m(chunk);
499 1.1 mrg if (m.allocated() && m.tag() != kReachable && m.tag() != kIgnored) {
500 1.1 mrg u32 stack_id = m.stack_trace_id();
501 1.1 mrg uptr caller_pc = 0;
502 1.1 mrg if (stack_id > 0)
503 1.3 mrg caller_pc = GetCallerPC(StackDepotGet(stack_id));
504 1.1 mrg // If caller_pc is unknown, this chunk may be allocated in a coroutine. Mark
505 1.1 mrg // it as reachable, as we can't properly report its allocation stack anyway.
506 1.1 mrg if (caller_pc == 0 || (param->skip_linker_allocations &&
507 1.1 mrg GetLinker()->containsAddress(caller_pc))) {
508 1.1 mrg m.set_tag(kReachable);
509 1.1 mrg param->frontier->push_back(chunk);
510 1.1 mrg }
511 1.1 mrg }
512 1.1 mrg }
513 1.1 mrg
514 1.1 mrg // On Linux, treats all chunks allocated from ld-linux.so as reachable, which
515 1.1 mrg // covers dynamically allocated TLS blocks, internal dynamic loader's loaded
516 1.1 mrg // modules accounting etc.
517 1.1 mrg // Dynamic TLS blocks contain the TLS variables of dynamically loaded modules.
518 1.1 mrg // They are allocated with a __libc_memalign() call in allocate_and_init()
519 1.1 mrg // (elf/dl-tls.c). Glibc won't tell us the address ranges occupied by those
520 1.1 mrg // blocks, but we can make sure they come from our own allocator by intercepting
521 1.1 mrg // __libc_memalign(). On top of that, there is no easy way to reach them. Their
522 1.1 mrg // addresses are stored in a dynamically allocated array (the DTV) which is
523 1.1 mrg // referenced from the static TLS. Unfortunately, we can't just rely on the DTV
524 1.1 mrg // being reachable from the static TLS, and the dynamic TLS being reachable from
525 1.1 mrg // the DTV. This is because the initial DTV is allocated before our interception
526 1.1 mrg // mechanism kicks in, and thus we don't recognize it as allocated memory. We
527 1.1 mrg // can't special-case it either, since we don't know its size.
528 1.1 mrg // Our solution is to include in the root set all allocations made from
529 1.1 mrg // ld-linux.so (which is where allocate_and_init() is implemented). This is
530 1.1 mrg // guaranteed to include all dynamic TLS blocks (and possibly other allocations
531 1.1 mrg // which we don't care about).
532 1.1 mrg // On all other platforms, this simply checks to ensure that the caller pc is
533 1.1 mrg // valid before reporting chunks as leaked.
534 1.3 mrg static void ProcessPC(Frontier *frontier) {
535 1.1 mrg InvalidPCParam arg;
536 1.1 mrg arg.frontier = frontier;
537 1.1 mrg arg.skip_linker_allocations =
538 1.1 mrg flags()->use_tls && flags()->use_ld_allocations && GetLinker() != nullptr;
539 1.1 mrg ForEachChunk(MarkInvalidPCCb, &arg);
540 1.1 mrg }
541 1.1 mrg
542 1.1 mrg // Sets the appropriate tag on each chunk.
543 1.3 mrg static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads,
544 1.3 mrg Frontier *frontier) {
545 1.3 mrg const InternalMmapVector<u32> &suppressed_stacks =
546 1.3 mrg GetSuppressionContext()->GetSortedSuppressedStacks();
547 1.3 mrg if (!suppressed_stacks.empty()) {
548 1.3 mrg ForEachChunk(IgnoredSuppressedCb,
549 1.3 mrg const_cast<InternalMmapVector<u32> *>(&suppressed_stacks));
550 1.3 mrg }
551 1.3 mrg ForEachChunk(CollectIgnoredCb, frontier);
552 1.3 mrg ProcessGlobalRegions(frontier);
553 1.3 mrg ProcessThreads(suspended_threads, frontier);
554 1.3 mrg ProcessRootRegions(frontier);
555 1.3 mrg FloodFillTag(frontier, kReachable);
556 1.1 mrg
557 1.3 mrg CHECK_EQ(0, frontier->size());
558 1.3 mrg ProcessPC(frontier);
559 1.1 mrg
560 1.1 mrg // The check here is relatively expensive, so we do this in a separate flood
561 1.1 mrg // fill. That way we can skip the check for chunks that are reachable
562 1.1 mrg // otherwise.
563 1.1 mrg LOG_POINTERS("Processing platform-specific allocations.\n");
564 1.3 mrg ProcessPlatformSpecificAllocations(frontier);
565 1.3 mrg FloodFillTag(frontier, kReachable);
566 1.1 mrg
567 1.1 mrg // Iterate over leaked chunks and mark those that are reachable from other
568 1.1 mrg // leaked chunks.
569 1.1 mrg LOG_POINTERS("Scanning leaked chunks.\n");
570 1.1 mrg ForEachChunk(MarkIndirectlyLeakedCb, nullptr);
571 1.1 mrg }
572 1.1 mrg
573 1.1 mrg // ForEachChunk callback. Resets the tags to pre-leak-check state.
574 1.1 mrg static void ResetTagsCb(uptr chunk, void *arg) {
575 1.1 mrg (void)arg;
576 1.1 mrg chunk = GetUserBegin(chunk);
577 1.1 mrg LsanMetadata m(chunk);
578 1.1 mrg if (m.allocated() && m.tag() != kIgnored)
579 1.1 mrg m.set_tag(kDirectlyLeaked);
580 1.1 mrg }
581 1.1 mrg
582 1.1 mrg // ForEachChunk callback. Aggregates information about unreachable chunks into
583 1.1 mrg // a LeakReport.
584 1.1 mrg static void CollectLeaksCb(uptr chunk, void *arg) {
585 1.1 mrg CHECK(arg);
586 1.1 mrg LeakReport *leak_report = reinterpret_cast<LeakReport *>(arg);
587 1.1 mrg chunk = GetUserBegin(chunk);
588 1.1 mrg LsanMetadata m(chunk);
589 1.1 mrg if (!m.allocated()) return;
590 1.1 mrg if (m.tag() == kDirectlyLeaked || m.tag() == kIndirectlyLeaked) {
591 1.3 mrg leak_report->AddLeakedChunk(chunk, m.stack_trace_id(), m.requested_size(),
592 1.1 mrg m.tag());
593 1.1 mrg }
594 1.1 mrg }
595 1.1 mrg
596 1.3 mrg void LeakSuppressionContext::PrintMatchedSuppressions() {
597 1.1 mrg InternalMmapVector<Suppression *> matched;
598 1.3 mrg context.GetMatched(&matched);
599 1.1 mrg if (!matched.size())
600 1.1 mrg return;
601 1.1 mrg const char *line = "-----------------------------------------------------";
602 1.1 mrg Printf("%s\n", line);
603 1.1 mrg Printf("Suppressions used:\n");
604 1.1 mrg Printf(" count bytes template\n");
605 1.3 mrg for (uptr i = 0; i < matched.size(); i++) {
606 1.3 mrg Printf("%7zu %10zu %s\n",
607 1.3 mrg static_cast<uptr>(atomic_load_relaxed(&matched[i]->hit_count)),
608 1.3 mrg matched[i]->weight, matched[i]->templ);
609 1.3 mrg }
610 1.1 mrg Printf("%s\n\n", line);
611 1.1 mrg }
612 1.1 mrg
613 1.1 mrg static void ReportIfNotSuspended(ThreadContextBase *tctx, void *arg) {
614 1.1 mrg const InternalMmapVector<tid_t> &suspended_threads =
615 1.1 mrg *(const InternalMmapVector<tid_t> *)arg;
616 1.1 mrg if (tctx->status == ThreadStatusRunning) {
617 1.3 mrg uptr i = InternalLowerBound(suspended_threads, tctx->os_id);
618 1.1 mrg if (i >= suspended_threads.size() || suspended_threads[i] != tctx->os_id)
619 1.3 mrg Report(
620 1.3 mrg "Running thread %llu was not suspended. False leaks are possible.\n",
621 1.3 mrg tctx->os_id);
622 1.1 mrg }
623 1.1 mrg }
624 1.1 mrg
625 1.3 mrg #if SANITIZER_FUCHSIA
626 1.3 mrg
627 1.3 mrg // Fuchsia provides a libc interface that guarantees all threads are
628 1.3 mrg // covered, and SuspendedThreadList is never really used.
629 1.3 mrg static void ReportUnsuspendedThreads(const SuspendedThreadsList &) {}
630 1.3 mrg
631 1.3 mrg #else // !SANITIZER_FUCHSIA
632 1.3 mrg
633 1.1 mrg static void ReportUnsuspendedThreads(
634 1.1 mrg const SuspendedThreadsList &suspended_threads) {
635 1.1 mrg InternalMmapVector<tid_t> threads(suspended_threads.ThreadCount());
636 1.1 mrg for (uptr i = 0; i < suspended_threads.ThreadCount(); ++i)
637 1.1 mrg threads[i] = suspended_threads.GetThreadID(i);
638 1.1 mrg
639 1.1 mrg Sort(threads.data(), threads.size());
640 1.1 mrg
641 1.1 mrg GetThreadRegistryLocked()->RunCallbackForEachThreadLocked(
642 1.1 mrg &ReportIfNotSuspended, &threads);
643 1.1 mrg }
644 1.1 mrg
645 1.3 mrg #endif // !SANITIZER_FUCHSIA
646 1.3 mrg
647 1.1 mrg static void CheckForLeaksCallback(const SuspendedThreadsList &suspended_threads,
648 1.1 mrg void *arg) {
649 1.1 mrg CheckForLeaksParam *param = reinterpret_cast<CheckForLeaksParam *>(arg);
650 1.1 mrg CHECK(param);
651 1.1 mrg CHECK(!param->success);
652 1.1 mrg ReportUnsuspendedThreads(suspended_threads);
653 1.3 mrg ClassifyAllChunks(suspended_threads, ¶m->frontier);
654 1.1 mrg ForEachChunk(CollectLeaksCb, ¶m->leak_report);
655 1.1 mrg // Clean up for subsequent leak checks. This assumes we did not overwrite any
656 1.1 mrg // kIgnored tags.
657 1.1 mrg ForEachChunk(ResetTagsCb, nullptr);
658 1.1 mrg param->success = true;
659 1.1 mrg }
660 1.1 mrg
661 1.3 mrg static bool PrintResults(LeakReport &report) {
662 1.3 mrg uptr unsuppressed_count = report.UnsuppressedLeakCount();
663 1.3 mrg if (unsuppressed_count) {
664 1.1 mrg Decorator d;
665 1.3 mrg Printf(
666 1.3 mrg "\n"
667 1.3 mrg "================================================================="
668 1.3 mrg "\n");
669 1.1 mrg Printf("%s", d.Error());
670 1.1 mrg Report("ERROR: LeakSanitizer: detected memory leaks\n");
671 1.1 mrg Printf("%s", d.Default());
672 1.3 mrg report.ReportTopLeaks(flags()->max_leaks);
673 1.1 mrg }
674 1.1 mrg if (common_flags()->print_suppressions)
675 1.3 mrg GetSuppressionContext()->PrintMatchedSuppressions();
676 1.1 mrg if (unsuppressed_count > 0) {
677 1.3 mrg report.PrintSummary();
678 1.1 mrg return true;
679 1.1 mrg }
680 1.1 mrg return false;
681 1.1 mrg }
682 1.1 mrg
683 1.3 mrg static bool CheckForLeaks() {
684 1.3 mrg if (&__lsan_is_turned_off && __lsan_is_turned_off())
685 1.3 mrg return false;
686 1.3 mrg // Inside LockStuffAndStopTheWorld we can't run symbolizer, so we can't match
687 1.3 mrg // suppressions. However if a stack id was previously suppressed, it should be
688 1.3 mrg // suppressed in future checks as well.
689 1.3 mrg for (int i = 0;; ++i) {
690 1.3 mrg EnsureMainThreadIDIsCorrect();
691 1.3 mrg CheckForLeaksParam param;
692 1.3 mrg LockStuffAndStopTheWorld(CheckForLeaksCallback, ¶m);
693 1.3 mrg if (!param.success) {
694 1.3 mrg Report("LeakSanitizer has encountered a fatal error.\n");
695 1.3 mrg Report(
696 1.3 mrg "HINT: For debugging, try setting environment variable "
697 1.3 mrg "LSAN_OPTIONS=verbosity=1:log_threads=1\n");
698 1.3 mrg Report(
699 1.3 mrg "HINT: LeakSanitizer does not work under ptrace (strace, gdb, "
700 1.3 mrg "etc)\n");
701 1.3 mrg Die();
702 1.3 mrg }
703 1.3 mrg // No new suppressions stacks, so rerun will not help and we can report.
704 1.3 mrg if (!param.leak_report.ApplySuppressions())
705 1.3 mrg return PrintResults(param.leak_report);
706 1.3 mrg
707 1.3 mrg // No indirect leaks to report, so we are done here.
708 1.3 mrg if (!param.leak_report.IndirectUnsuppressedLeakCount())
709 1.3 mrg return PrintResults(param.leak_report);
710 1.3 mrg
711 1.3 mrg if (i >= 8) {
712 1.3 mrg Report("WARNING: LeakSanitizer gave up on indirect leaks suppression.\n");
713 1.3 mrg return PrintResults(param.leak_report);
714 1.3 mrg }
715 1.3 mrg
716 1.3 mrg // We found a new previously unseen suppressed call stack. Rerun to make
717 1.3 mrg // sure it does not hold indirect leaks.
718 1.3 mrg VReport(1, "Rerun with %zu suppressed stacks.",
719 1.3 mrg GetSuppressionContext()->GetSortedSuppressedStacks().size());
720 1.3 mrg }
721 1.3 mrg }
722 1.3 mrg
723 1.1 mrg static bool has_reported_leaks = false;
724 1.1 mrg bool HasReportedLeaks() { return has_reported_leaks; }
725 1.1 mrg
726 1.1 mrg void DoLeakCheck() {
727 1.3 mrg Lock l(&global_mutex);
728 1.1 mrg static bool already_done;
729 1.1 mrg if (already_done) return;
730 1.1 mrg already_done = true;
731 1.1 mrg has_reported_leaks = CheckForLeaks();
732 1.1 mrg if (has_reported_leaks) HandleLeaks();
733 1.1 mrg }
734 1.1 mrg
735 1.1 mrg static int DoRecoverableLeakCheck() {
736 1.3 mrg Lock l(&global_mutex);
737 1.1 mrg bool have_leaks = CheckForLeaks();
738 1.1 mrg return have_leaks ? 1 : 0;
739 1.1 mrg }
740 1.1 mrg
741 1.1 mrg void DoRecoverableLeakCheckVoid() { DoRecoverableLeakCheck(); }
742 1.1 mrg
743 1.3 mrg Suppression *LeakSuppressionContext::GetSuppressionForAddr(uptr addr) {
744 1.1 mrg Suppression *s = nullptr;
745 1.1 mrg
746 1.1 mrg // Suppress by module name.
747 1.1 mrg if (const char *module_name =
748 1.1 mrg Symbolizer::GetOrInit()->GetModuleNameForPc(addr))
749 1.3 mrg if (context.Match(module_name, kSuppressionLeak, &s))
750 1.1 mrg return s;
751 1.1 mrg
752 1.1 mrg // Suppress by file or function name.
753 1.1 mrg SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(addr);
754 1.1 mrg for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
755 1.3 mrg if (context.Match(cur->info.function, kSuppressionLeak, &s) ||
756 1.3 mrg context.Match(cur->info.file, kSuppressionLeak, &s)) {
757 1.1 mrg break;
758 1.1 mrg }
759 1.1 mrg }
760 1.1 mrg frames->ClearAll();
761 1.1 mrg return s;
762 1.1 mrg }
763 1.1 mrg
764 1.3 mrg Suppression *LeakSuppressionContext::GetSuppressionForStack(
765 1.3 mrg u32 stack_trace_id, const StackTrace &stack) {
766 1.3 mrg LazyInit();
767 1.1 mrg for (uptr i = 0; i < stack.size; i++) {
768 1.1 mrg Suppression *s = GetSuppressionForAddr(
769 1.1 mrg StackTrace::GetPreviousInstructionPc(stack.trace[i]));
770 1.3 mrg if (s) {
771 1.3 mrg suppressed_stacks_sorted = false;
772 1.3 mrg suppressed_stacks.push_back(stack_trace_id);
773 1.3 mrg return s;
774 1.3 mrg }
775 1.1 mrg }
776 1.1 mrg return nullptr;
777 1.1 mrg }
778 1.1 mrg
779 1.1 mrg ///// LeakReport implementation. /////
780 1.1 mrg
781 1.1 mrg // A hard limit on the number of distinct leaks, to avoid quadratic complexity
782 1.1 mrg // in LeakReport::AddLeakedChunk(). We don't expect to ever see this many leaks
783 1.1 mrg // in real-world applications.
784 1.1 mrg // FIXME: Get rid of this limit by changing the implementation of LeakReport to
785 1.1 mrg // use a hash table.
786 1.1 mrg const uptr kMaxLeaksConsidered = 5000;
787 1.1 mrg
788 1.1 mrg void LeakReport::AddLeakedChunk(uptr chunk, u32 stack_trace_id,
789 1.1 mrg uptr leaked_size, ChunkTag tag) {
790 1.1 mrg CHECK(tag == kDirectlyLeaked || tag == kIndirectlyLeaked);
791 1.3 mrg
792 1.3 mrg if (u32 resolution = flags()->resolution) {
793 1.3 mrg StackTrace stack = StackDepotGet(stack_trace_id);
794 1.3 mrg stack.size = Min(stack.size, resolution);
795 1.3 mrg stack_trace_id = StackDepotPut(stack);
796 1.3 mrg }
797 1.3 mrg
798 1.1 mrg bool is_directly_leaked = (tag == kDirectlyLeaked);
799 1.1 mrg uptr i;
800 1.1 mrg for (i = 0; i < leaks_.size(); i++) {
801 1.1 mrg if (leaks_[i].stack_trace_id == stack_trace_id &&
802 1.1 mrg leaks_[i].is_directly_leaked == is_directly_leaked) {
803 1.1 mrg leaks_[i].hit_count++;
804 1.1 mrg leaks_[i].total_size += leaked_size;
805 1.1 mrg break;
806 1.1 mrg }
807 1.1 mrg }
808 1.1 mrg if (i == leaks_.size()) {
809 1.1 mrg if (leaks_.size() == kMaxLeaksConsidered) return;
810 1.1 mrg Leak leak = { next_id_++, /* hit_count */ 1, leaked_size, stack_trace_id,
811 1.1 mrg is_directly_leaked, /* is_suppressed */ false };
812 1.1 mrg leaks_.push_back(leak);
813 1.1 mrg }
814 1.1 mrg if (flags()->report_objects) {
815 1.1 mrg LeakedObject obj = {leaks_[i].id, chunk, leaked_size};
816 1.1 mrg leaked_objects_.push_back(obj);
817 1.1 mrg }
818 1.1 mrg }
819 1.1 mrg
820 1.1 mrg static bool LeakComparator(const Leak &leak1, const Leak &leak2) {
821 1.1 mrg if (leak1.is_directly_leaked == leak2.is_directly_leaked)
822 1.1 mrg return leak1.total_size > leak2.total_size;
823 1.1 mrg else
824 1.1 mrg return leak1.is_directly_leaked;
825 1.1 mrg }
826 1.1 mrg
827 1.1 mrg void LeakReport::ReportTopLeaks(uptr num_leaks_to_report) {
828 1.1 mrg CHECK(leaks_.size() <= kMaxLeaksConsidered);
829 1.1 mrg Printf("\n");
830 1.1 mrg if (leaks_.size() == kMaxLeaksConsidered)
831 1.1 mrg Printf("Too many leaks! Only the first %zu leaks encountered will be "
832 1.1 mrg "reported.\n",
833 1.1 mrg kMaxLeaksConsidered);
834 1.1 mrg
835 1.1 mrg uptr unsuppressed_count = UnsuppressedLeakCount();
836 1.1 mrg if (num_leaks_to_report > 0 && num_leaks_to_report < unsuppressed_count)
837 1.1 mrg Printf("The %zu top leak(s):\n", num_leaks_to_report);
838 1.1 mrg Sort(leaks_.data(), leaks_.size(), &LeakComparator);
839 1.1 mrg uptr leaks_reported = 0;
840 1.1 mrg for (uptr i = 0; i < leaks_.size(); i++) {
841 1.1 mrg if (leaks_[i].is_suppressed) continue;
842 1.1 mrg PrintReportForLeak(i);
843 1.1 mrg leaks_reported++;
844 1.1 mrg if (leaks_reported == num_leaks_to_report) break;
845 1.1 mrg }
846 1.1 mrg if (leaks_reported < unsuppressed_count) {
847 1.1 mrg uptr remaining = unsuppressed_count - leaks_reported;
848 1.1 mrg Printf("Omitting %zu more leak(s).\n", remaining);
849 1.1 mrg }
850 1.1 mrg }
851 1.1 mrg
852 1.1 mrg void LeakReport::PrintReportForLeak(uptr index) {
853 1.1 mrg Decorator d;
854 1.1 mrg Printf("%s", d.Leak());
855 1.1 mrg Printf("%s leak of %zu byte(s) in %zu object(s) allocated from:\n",
856 1.1 mrg leaks_[index].is_directly_leaked ? "Direct" : "Indirect",
857 1.1 mrg leaks_[index].total_size, leaks_[index].hit_count);
858 1.1 mrg Printf("%s", d.Default());
859 1.1 mrg
860 1.3 mrg CHECK(leaks_[index].stack_trace_id);
861 1.3 mrg StackDepotGet(leaks_[index].stack_trace_id).Print();
862 1.1 mrg
863 1.1 mrg if (flags()->report_objects) {
864 1.1 mrg Printf("Objects leaked above:\n");
865 1.1 mrg PrintLeakedObjectsForLeak(index);
866 1.1 mrg Printf("\n");
867 1.1 mrg }
868 1.1 mrg }
869 1.1 mrg
870 1.1 mrg void LeakReport::PrintLeakedObjectsForLeak(uptr index) {
871 1.1 mrg u32 leak_id = leaks_[index].id;
872 1.1 mrg for (uptr j = 0; j < leaked_objects_.size(); j++) {
873 1.1 mrg if (leaked_objects_[j].leak_id == leak_id)
874 1.3 mrg Printf("%p (%zu bytes)\n", (void *)leaked_objects_[j].addr,
875 1.1 mrg leaked_objects_[j].size);
876 1.1 mrg }
877 1.1 mrg }
878 1.1 mrg
879 1.1 mrg void LeakReport::PrintSummary() {
880 1.1 mrg CHECK(leaks_.size() <= kMaxLeaksConsidered);
881 1.1 mrg uptr bytes = 0, allocations = 0;
882 1.1 mrg for (uptr i = 0; i < leaks_.size(); i++) {
883 1.1 mrg if (leaks_[i].is_suppressed) continue;
884 1.1 mrg bytes += leaks_[i].total_size;
885 1.1 mrg allocations += leaks_[i].hit_count;
886 1.1 mrg }
887 1.3 mrg InternalScopedString summary;
888 1.1 mrg summary.append("%zu byte(s) leaked in %zu allocation(s).", bytes,
889 1.1 mrg allocations);
890 1.1 mrg ReportErrorSummary(summary.data());
891 1.1 mrg }
892 1.1 mrg
893 1.3 mrg uptr LeakReport::ApplySuppressions() {
894 1.3 mrg LeakSuppressionContext *suppressions = GetSuppressionContext();
895 1.3 mrg uptr new_suppressions = false;
896 1.1 mrg for (uptr i = 0; i < leaks_.size(); i++) {
897 1.3 mrg Suppression *s = suppressions->GetSuppressionForStack(
898 1.3 mrg leaks_[i].stack_trace_id, StackDepotGet(leaks_[i].stack_trace_id));
899 1.1 mrg if (s) {
900 1.1 mrg s->weight += leaks_[i].total_size;
901 1.1 mrg atomic_store_relaxed(&s->hit_count, atomic_load_relaxed(&s->hit_count) +
902 1.1 mrg leaks_[i].hit_count);
903 1.1 mrg leaks_[i].is_suppressed = true;
904 1.3 mrg ++new_suppressions;
905 1.1 mrg }
906 1.1 mrg }
907 1.3 mrg return new_suppressions;
908 1.1 mrg }
909 1.1 mrg
910 1.1 mrg uptr LeakReport::UnsuppressedLeakCount() {
911 1.1 mrg uptr result = 0;
912 1.1 mrg for (uptr i = 0; i < leaks_.size(); i++)
913 1.1 mrg if (!leaks_[i].is_suppressed) result++;
914 1.1 mrg return result;
915 1.1 mrg }
916 1.1 mrg
917 1.3 mrg uptr LeakReport::IndirectUnsuppressedLeakCount() {
918 1.3 mrg uptr result = 0;
919 1.3 mrg for (uptr i = 0; i < leaks_.size(); i++)
920 1.3 mrg if (!leaks_[i].is_suppressed && !leaks_[i].is_directly_leaked)
921 1.3 mrg result++;
922 1.3 mrg return result;
923 1.3 mrg }
924 1.3 mrg
925 1.1 mrg } // namespace __lsan
926 1.1 mrg #else // CAN_SANITIZE_LEAKS
927 1.1 mrg namespace __lsan {
928 1.1 mrg void InitCommonLsan() { }
929 1.1 mrg void DoLeakCheck() { }
930 1.1 mrg void DoRecoverableLeakCheckVoid() { }
931 1.1 mrg void DisableInThisThread() { }
932 1.1 mrg void EnableInThisThread() { }
933 1.1 mrg }
934 1.1 mrg #endif // CAN_SANITIZE_LEAKS
935 1.1 mrg
936 1.1 mrg using namespace __lsan;
937 1.1 mrg
938 1.1 mrg extern "C" {
939 1.1 mrg SANITIZER_INTERFACE_ATTRIBUTE
940 1.1 mrg void __lsan_ignore_object(const void *p) {
941 1.1 mrg #if CAN_SANITIZE_LEAKS
942 1.1 mrg if (!common_flags()->detect_leaks)
943 1.1 mrg return;
944 1.1 mrg // Cannot use PointsIntoChunk or LsanMetadata here, since the allocator is not
945 1.1 mrg // locked.
946 1.3 mrg Lock l(&global_mutex);
947 1.1 mrg IgnoreObjectResult res = IgnoreObjectLocked(p);
948 1.1 mrg if (res == kIgnoreObjectInvalid)
949 1.1 mrg VReport(1, "__lsan_ignore_object(): no heap object found at %p", p);
950 1.1 mrg if (res == kIgnoreObjectAlreadyIgnored)
951 1.1 mrg VReport(1, "__lsan_ignore_object(): "
952 1.1 mrg "heap object at %p is already being ignored\n", p);
953 1.1 mrg if (res == kIgnoreObjectSuccess)
954 1.1 mrg VReport(1, "__lsan_ignore_object(): ignoring heap object at %p\n", p);
955 1.1 mrg #endif // CAN_SANITIZE_LEAKS
956 1.1 mrg }
957 1.1 mrg
958 1.1 mrg SANITIZER_INTERFACE_ATTRIBUTE
959 1.1 mrg void __lsan_register_root_region(const void *begin, uptr size) {
960 1.1 mrg #if CAN_SANITIZE_LEAKS
961 1.3 mrg Lock l(&global_mutex);
962 1.1 mrg RootRegion region = {reinterpret_cast<uptr>(begin), size};
963 1.3 mrg root_regions.push_back(region);
964 1.3 mrg VReport(1, "Registered root region at %p of size %zu\n", begin, size);
965 1.1 mrg #endif // CAN_SANITIZE_LEAKS
966 1.1 mrg }
967 1.1 mrg
968 1.1 mrg SANITIZER_INTERFACE_ATTRIBUTE
969 1.1 mrg void __lsan_unregister_root_region(const void *begin, uptr size) {
970 1.1 mrg #if CAN_SANITIZE_LEAKS
971 1.3 mrg Lock l(&global_mutex);
972 1.1 mrg bool removed = false;
973 1.3 mrg for (uptr i = 0; i < root_regions.size(); i++) {
974 1.3 mrg RootRegion region = root_regions[i];
975 1.1 mrg if (region.begin == reinterpret_cast<uptr>(begin) && region.size == size) {
976 1.1 mrg removed = true;
977 1.3 mrg uptr last_index = root_regions.size() - 1;
978 1.3 mrg root_regions[i] = root_regions[last_index];
979 1.3 mrg root_regions.pop_back();
980 1.3 mrg VReport(1, "Unregistered root region at %p of size %zu\n", begin, size);
981 1.1 mrg break;
982 1.1 mrg }
983 1.1 mrg }
984 1.1 mrg if (!removed) {
985 1.1 mrg Report(
986 1.3 mrg "__lsan_unregister_root_region(): region at %p of size %zu has not "
987 1.1 mrg "been registered.\n",
988 1.1 mrg begin, size);
989 1.1 mrg Die();
990 1.1 mrg }
991 1.1 mrg #endif // CAN_SANITIZE_LEAKS
992 1.1 mrg }
993 1.1 mrg
994 1.1 mrg SANITIZER_INTERFACE_ATTRIBUTE
995 1.1 mrg void __lsan_disable() {
996 1.1 mrg #if CAN_SANITIZE_LEAKS
997 1.1 mrg __lsan::DisableInThisThread();
998 1.1 mrg #endif
999 1.1 mrg }
1000 1.1 mrg
1001 1.1 mrg SANITIZER_INTERFACE_ATTRIBUTE
1002 1.1 mrg void __lsan_enable() {
1003 1.1 mrg #if CAN_SANITIZE_LEAKS
1004 1.1 mrg __lsan::EnableInThisThread();
1005 1.1 mrg #endif
1006 1.1 mrg }
1007 1.1 mrg
1008 1.1 mrg SANITIZER_INTERFACE_ATTRIBUTE
1009 1.1 mrg void __lsan_do_leak_check() {
1010 1.1 mrg #if CAN_SANITIZE_LEAKS
1011 1.1 mrg if (common_flags()->detect_leaks)
1012 1.1 mrg __lsan::DoLeakCheck();
1013 1.1 mrg #endif // CAN_SANITIZE_LEAKS
1014 1.1 mrg }
1015 1.1 mrg
1016 1.1 mrg SANITIZER_INTERFACE_ATTRIBUTE
1017 1.1 mrg int __lsan_do_recoverable_leak_check() {
1018 1.1 mrg #if CAN_SANITIZE_LEAKS
1019 1.1 mrg if (common_flags()->detect_leaks)
1020 1.1 mrg return __lsan::DoRecoverableLeakCheck();
1021 1.1 mrg #endif // CAN_SANITIZE_LEAKS
1022 1.1 mrg return 0;
1023 1.1 mrg }
1024 1.1 mrg
1025 1.3 mrg SANITIZER_INTERFACE_WEAK_DEF(const char *, __lsan_default_options, void) {
1026 1.1 mrg return "";
1027 1.1 mrg }
1028 1.1 mrg
1029 1.3 mrg #if !SANITIZER_SUPPORTS_WEAK_HOOKS
1030 1.1 mrg SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
1031 1.1 mrg int __lsan_is_turned_off() {
1032 1.1 mrg return 0;
1033 1.1 mrg }
1034 1.1 mrg
1035 1.1 mrg SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
1036 1.1 mrg const char *__lsan_default_suppressions() {
1037 1.1 mrg return "";
1038 1.1 mrg }
1039 1.1 mrg #endif
1040 1.1 mrg } // extern "C"
1041