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