1 | //=-- lsan_interceptors.cpp -----------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file is a part of LeakSanitizer. |
10 | // Interceptors for standalone LSan. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "interception/interception.h" |
15 | #include "sanitizer_common/sanitizer_allocator.h" |
16 | #include "sanitizer_common/sanitizer_allocator_dlsym.h" |
17 | #include "sanitizer_common/sanitizer_allocator_report.h" |
18 | #include "sanitizer_common/sanitizer_atomic.h" |
19 | #include "sanitizer_common/sanitizer_common.h" |
20 | #include "sanitizer_common/sanitizer_flags.h" |
21 | #include "sanitizer_common/sanitizer_internal_defs.h" |
22 | #include "sanitizer_common/sanitizer_linux.h" |
23 | #include "sanitizer_common/sanitizer_platform_interceptors.h" |
24 | #include "sanitizer_common/sanitizer_platform_limits_netbsd.h" |
25 | #include "sanitizer_common/sanitizer_platform_limits_posix.h" |
26 | #if SANITIZER_POSIX |
27 | #include "sanitizer_common/sanitizer_posix.h" |
28 | #endif |
29 | #include "lsan.h" |
30 | #include "lsan_allocator.h" |
31 | #include "lsan_common.h" |
32 | #include "lsan_thread.h" |
33 | |
34 | #include <stddef.h> |
35 | |
36 | using namespace __lsan; |
37 | |
38 | extern "C" { |
39 | int pthread_attr_init(void *attr); |
40 | int pthread_attr_destroy(void *attr); |
41 | int pthread_attr_getdetachstate(void *attr, int *v); |
42 | int pthread_key_create(unsigned *key, void (*destructor)(void* v)); |
43 | int pthread_setspecific(unsigned key, const void *v); |
44 | } |
45 | |
46 | struct DlsymAlloc : DlSymAllocator<DlsymAlloc> { |
47 | static bool UseImpl() { return lsan_init_is_running; } |
48 | static void OnAllocate(const void *ptr, uptr size) { |
49 | #if CAN_SANITIZE_LEAKS |
50 | // Suppress leaks from dlerror(). Previously dlsym hack on global array was |
51 | // used by leak sanitizer as a root region. |
52 | __lsan_register_root_region(p: ptr, size); |
53 | #endif |
54 | } |
55 | static void OnFree(const void *ptr, uptr size) { |
56 | #if CAN_SANITIZE_LEAKS |
57 | __lsan_unregister_root_region(p: ptr, size); |
58 | #endif |
59 | } |
60 | }; |
61 | |
62 | ///// Malloc/free interceptors. ///// |
63 | |
64 | namespace std { |
65 | struct nothrow_t; |
66 | enum class align_val_t: size_t; |
67 | } |
68 | |
69 | #if !SANITIZER_APPLE |
70 | INTERCEPTOR(void*, malloc, uptr size) { |
71 | if (DlsymAlloc::Use()) |
72 | return DlsymAlloc::Allocate(size_in_bytes: size); |
73 | ENSURE_LSAN_INITED; |
74 | GET_STACK_TRACE_MALLOC; |
75 | return lsan_malloc(size, stack); |
76 | } |
77 | |
78 | INTERCEPTOR(void, free, void *p) { |
79 | if (UNLIKELY(!p)) |
80 | return; |
81 | if (DlsymAlloc::PointerIsMine(ptr: p)) |
82 | return DlsymAlloc::Free(ptr: p); |
83 | ENSURE_LSAN_INITED; |
84 | lsan_free(p); |
85 | } |
86 | |
87 | INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { |
88 | if (DlsymAlloc::Use()) |
89 | return DlsymAlloc::Callocate(nmemb, size); |
90 | ENSURE_LSAN_INITED; |
91 | GET_STACK_TRACE_MALLOC; |
92 | return lsan_calloc(nmemb, size, stack); |
93 | } |
94 | |
95 | INTERCEPTOR(void *, realloc, void *ptr, uptr size) { |
96 | if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr)) |
97 | return DlsymAlloc::Realloc(ptr, new_size: size); |
98 | ENSURE_LSAN_INITED; |
99 | GET_STACK_TRACE_MALLOC; |
100 | return lsan_realloc(p: ptr, size, stack); |
101 | } |
102 | |
103 | INTERCEPTOR(void*, reallocarray, void *q, uptr nmemb, uptr size) { |
104 | ENSURE_LSAN_INITED; |
105 | GET_STACK_TRACE_MALLOC; |
106 | return lsan_reallocarray(p: q, nmemb, size, stack); |
107 | } |
108 | |
109 | INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) { |
110 | ENSURE_LSAN_INITED; |
111 | GET_STACK_TRACE_MALLOC; |
112 | return lsan_posix_memalign(memptr, alignment, size, stack); |
113 | } |
114 | |
115 | INTERCEPTOR(void*, valloc, uptr size) { |
116 | ENSURE_LSAN_INITED; |
117 | GET_STACK_TRACE_MALLOC; |
118 | return lsan_valloc(size, stack); |
119 | } |
120 | #endif // !SANITIZER_APPLE |
121 | |
122 | #if SANITIZER_INTERCEPT_MEMALIGN |
123 | INTERCEPTOR(void*, memalign, uptr alignment, uptr size) { |
124 | ENSURE_LSAN_INITED; |
125 | GET_STACK_TRACE_MALLOC; |
126 | return lsan_memalign(alignment, size, stack); |
127 | } |
128 | #define LSAN_MAYBE_INTERCEPT_MEMALIGN INTERCEPT_FUNCTION(memalign) |
129 | #else |
130 | #define LSAN_MAYBE_INTERCEPT_MEMALIGN |
131 | #endif // SANITIZER_INTERCEPT_MEMALIGN |
132 | |
133 | #if SANITIZER_INTERCEPT___LIBC_MEMALIGN |
134 | INTERCEPTOR(void *, __libc_memalign, uptr alignment, uptr size) { |
135 | ENSURE_LSAN_INITED; |
136 | GET_STACK_TRACE_MALLOC; |
137 | return lsan_memalign(alignment, size, stack); |
138 | } |
139 | #define LSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN INTERCEPT_FUNCTION(__libc_memalign) |
140 | #else |
141 | #define LSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN |
142 | #endif // SANITIZER_INTERCEPT___LIBC_MEMALIGN |
143 | |
144 | #if SANITIZER_INTERCEPT_ALIGNED_ALLOC |
145 | INTERCEPTOR(void*, aligned_alloc, uptr alignment, uptr size) { |
146 | ENSURE_LSAN_INITED; |
147 | GET_STACK_TRACE_MALLOC; |
148 | return lsan_aligned_alloc(alignment, size, stack); |
149 | } |
150 | #define LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC INTERCEPT_FUNCTION(aligned_alloc) |
151 | #else |
152 | #define LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC |
153 | #endif |
154 | |
155 | #if SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE |
156 | INTERCEPTOR(uptr, malloc_usable_size, void *ptr) { |
157 | ENSURE_LSAN_INITED; |
158 | return GetMallocUsableSize(p: ptr); |
159 | } |
160 | #define LSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE \ |
161 | INTERCEPT_FUNCTION(malloc_usable_size) |
162 | #else |
163 | #define LSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE |
164 | #endif |
165 | |
166 | #if SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO |
167 | struct fake_mallinfo { |
168 | int x[10]; |
169 | }; |
170 | |
171 | INTERCEPTOR(struct fake_mallinfo, mallinfo, void) { |
172 | struct fake_mallinfo res; |
173 | internal_memset(s: &res, c: 0, n: sizeof(res)); |
174 | return res; |
175 | } |
176 | #define LSAN_MAYBE_INTERCEPT_MALLINFO INTERCEPT_FUNCTION(mallinfo) |
177 | |
178 | INTERCEPTOR(int, mallopt, int cmd, int value) { |
179 | return 0; |
180 | } |
181 | #define LSAN_MAYBE_INTERCEPT_MALLOPT INTERCEPT_FUNCTION(mallopt) |
182 | #else |
183 | #define LSAN_MAYBE_INTERCEPT_MALLINFO |
184 | #define LSAN_MAYBE_INTERCEPT_MALLOPT |
185 | #endif // SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO |
186 | |
187 | #if SANITIZER_INTERCEPT_PVALLOC |
188 | INTERCEPTOR(void*, pvalloc, uptr size) { |
189 | ENSURE_LSAN_INITED; |
190 | GET_STACK_TRACE_MALLOC; |
191 | return lsan_pvalloc(size, stack); |
192 | } |
193 | #define LSAN_MAYBE_INTERCEPT_PVALLOC INTERCEPT_FUNCTION(pvalloc) |
194 | #else |
195 | #define LSAN_MAYBE_INTERCEPT_PVALLOC |
196 | #endif // SANITIZER_INTERCEPT_PVALLOC |
197 | |
198 | #if SANITIZER_INTERCEPT_CFREE |
199 | INTERCEPTOR(void, cfree, void *p) ALIAS(WRAP(free)); |
200 | #define LSAN_MAYBE_INTERCEPT_CFREE INTERCEPT_FUNCTION(cfree) |
201 | #else |
202 | #define LSAN_MAYBE_INTERCEPT_CFREE |
203 | #endif // SANITIZER_INTERCEPT_CFREE |
204 | |
205 | #if SANITIZER_INTERCEPT_MCHECK_MPROBE |
206 | INTERCEPTOR(int, mcheck, void (*abortfunc)(int mstatus)) { |
207 | return 0; |
208 | } |
209 | |
210 | INTERCEPTOR(int, mcheck_pedantic, void (*abortfunc)(int mstatus)) { |
211 | return 0; |
212 | } |
213 | |
214 | INTERCEPTOR(int, mprobe, void *ptr) { |
215 | return 0; |
216 | } |
217 | #endif // SANITIZER_INTERCEPT_MCHECK_MPROBE |
218 | |
219 | |
220 | // TODO(alekseys): throw std::bad_alloc instead of dying on OOM. |
221 | #define OPERATOR_NEW_BODY(nothrow)\ |
222 | ENSURE_LSAN_INITED;\ |
223 | GET_STACK_TRACE_MALLOC;\ |
224 | void *res = lsan_malloc(size, stack);\ |
225 | if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\ |
226 | return res; |
227 | #define OPERATOR_NEW_BODY_ALIGN(nothrow)\ |
228 | ENSURE_LSAN_INITED;\ |
229 | GET_STACK_TRACE_MALLOC;\ |
230 | void *res = lsan_memalign((uptr)align, size, stack);\ |
231 | if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\ |
232 | return res; |
233 | |
234 | #define OPERATOR_DELETE_BODY\ |
235 | ENSURE_LSAN_INITED;\ |
236 | lsan_free(ptr); |
237 | |
238 | // On OS X it's not enough to just provide our own 'operator new' and |
239 | // 'operator delete' implementations, because they're going to be in the runtime |
240 | // dylib, and the main executable will depend on both the runtime dylib and |
241 | // libstdc++, each of has its implementation of new and delete. |
242 | // To make sure that C++ allocation/deallocation operators are overridden on |
243 | // OS X we need to intercept them using their mangled names. |
244 | #if !SANITIZER_APPLE |
245 | |
246 | INTERCEPTOR_ATTRIBUTE |
247 | void *operator new(size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); } |
248 | INTERCEPTOR_ATTRIBUTE |
249 | void *operator new[](size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); } |
250 | INTERCEPTOR_ATTRIBUTE |
251 | void *operator new(size_t size, std::nothrow_t const&) |
252 | { OPERATOR_NEW_BODY(true /*nothrow*/); } |
253 | INTERCEPTOR_ATTRIBUTE |
254 | void *operator new[](size_t size, std::nothrow_t const&) |
255 | { OPERATOR_NEW_BODY(true /*nothrow*/); } |
256 | INTERCEPTOR_ATTRIBUTE |
257 | void *operator new(size_t size, std::align_val_t align) |
258 | { OPERATOR_NEW_BODY_ALIGN(false /*nothrow*/); } |
259 | INTERCEPTOR_ATTRIBUTE |
260 | void *operator new[](size_t size, std::align_val_t align) |
261 | { OPERATOR_NEW_BODY_ALIGN(false /*nothrow*/); } |
262 | INTERCEPTOR_ATTRIBUTE |
263 | void *operator new(size_t size, std::align_val_t align, std::nothrow_t const&) |
264 | { OPERATOR_NEW_BODY_ALIGN(true /*nothrow*/); } |
265 | INTERCEPTOR_ATTRIBUTE |
266 | void *operator new[](size_t size, std::align_val_t align, std::nothrow_t const&) |
267 | { OPERATOR_NEW_BODY_ALIGN(true /*nothrow*/); } |
268 | |
269 | INTERCEPTOR_ATTRIBUTE |
270 | void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; } |
271 | INTERCEPTOR_ATTRIBUTE |
272 | void operator delete[](void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; } |
273 | INTERCEPTOR_ATTRIBUTE |
274 | void operator delete(void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY; } |
275 | INTERCEPTOR_ATTRIBUTE |
276 | void operator delete[](void *ptr, std::nothrow_t const &) |
277 | { OPERATOR_DELETE_BODY; } |
278 | INTERCEPTOR_ATTRIBUTE |
279 | void operator delete(void *ptr, size_t size) NOEXCEPT |
280 | { OPERATOR_DELETE_BODY; } |
281 | INTERCEPTOR_ATTRIBUTE |
282 | void operator delete[](void *ptr, size_t size) NOEXCEPT |
283 | { OPERATOR_DELETE_BODY; } |
284 | INTERCEPTOR_ATTRIBUTE |
285 | void operator delete(void *ptr, std::align_val_t) NOEXCEPT |
286 | { OPERATOR_DELETE_BODY; } |
287 | INTERCEPTOR_ATTRIBUTE |
288 | void operator delete[](void *ptr, std::align_val_t) NOEXCEPT |
289 | { OPERATOR_DELETE_BODY; } |
290 | INTERCEPTOR_ATTRIBUTE |
291 | void operator delete(void *ptr, std::align_val_t, std::nothrow_t const&) |
292 | { OPERATOR_DELETE_BODY; } |
293 | INTERCEPTOR_ATTRIBUTE |
294 | void operator delete[](void *ptr, std::align_val_t, std::nothrow_t const&) |
295 | { OPERATOR_DELETE_BODY; } |
296 | INTERCEPTOR_ATTRIBUTE |
297 | void operator delete(void *ptr, size_t size, std::align_val_t) NOEXCEPT |
298 | { OPERATOR_DELETE_BODY; } |
299 | INTERCEPTOR_ATTRIBUTE |
300 | void operator delete[](void *ptr, size_t size, std::align_val_t) NOEXCEPT |
301 | { OPERATOR_DELETE_BODY; } |
302 | |
303 | #else // SANITIZER_APPLE |
304 | |
305 | INTERCEPTOR(void *, _Znwm, size_t size) |
306 | { OPERATOR_NEW_BODY(false /*nothrow*/); } |
307 | INTERCEPTOR(void *, _Znam, size_t size) |
308 | { OPERATOR_NEW_BODY(false /*nothrow*/); } |
309 | INTERCEPTOR(void *, _ZnwmRKSt9nothrow_t, size_t size, std::nothrow_t const&) |
310 | { OPERATOR_NEW_BODY(true /*nothrow*/); } |
311 | INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) |
312 | { OPERATOR_NEW_BODY(true /*nothrow*/); } |
313 | |
314 | INTERCEPTOR(void, _ZdlPv, void *ptr) |
315 | { OPERATOR_DELETE_BODY; } |
316 | INTERCEPTOR(void, _ZdaPv, void *ptr) |
317 | { OPERATOR_DELETE_BODY; } |
318 | INTERCEPTOR(void, _ZdlPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&) |
319 | { OPERATOR_DELETE_BODY; } |
320 | INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&) |
321 | { OPERATOR_DELETE_BODY; } |
322 | |
323 | #endif // !SANITIZER_APPLE |
324 | |
325 | |
326 | ///// Thread initialization and finalization. ///// |
327 | |
328 | #if !SANITIZER_NETBSD && !SANITIZER_FREEBSD && !SANITIZER_FUCHSIA |
329 | static unsigned g_thread_finalize_key; |
330 | |
331 | static void thread_finalize(void *v) { |
332 | uptr iter = (uptr)v; |
333 | if (iter > 1) { |
334 | if (pthread_setspecific(key: g_thread_finalize_key, v: (void*)(iter - 1))) { |
335 | Report(format: "LeakSanitizer: failed to set thread key.\n" ); |
336 | Die(); |
337 | } |
338 | return; |
339 | } |
340 | ThreadFinish(); |
341 | } |
342 | #endif |
343 | |
344 | #if SANITIZER_NETBSD |
345 | INTERCEPTOR(void, _lwp_exit) { |
346 | ENSURE_LSAN_INITED; |
347 | ThreadFinish(); |
348 | REAL(_lwp_exit)(); |
349 | } |
350 | #define LSAN_MAYBE_INTERCEPT__LWP_EXIT INTERCEPT_FUNCTION(_lwp_exit) |
351 | #else |
352 | #define LSAN_MAYBE_INTERCEPT__LWP_EXIT |
353 | #endif |
354 | |
355 | #if SANITIZER_INTERCEPT_THR_EXIT |
356 | INTERCEPTOR(void, thr_exit, tid_t *state) { |
357 | ENSURE_LSAN_INITED; |
358 | ThreadFinish(); |
359 | REAL(thr_exit)(state); |
360 | } |
361 | #define LSAN_MAYBE_INTERCEPT_THR_EXIT INTERCEPT_FUNCTION(thr_exit) |
362 | #else |
363 | #define LSAN_MAYBE_INTERCEPT_THR_EXIT |
364 | #endif |
365 | |
366 | #if SANITIZER_INTERCEPT___CXA_ATEXIT |
367 | INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg, |
368 | void *dso_handle) { |
369 | __lsan::ScopedInterceptorDisabler disabler; |
370 | return REAL(__cxa_atexit)(func, arg, dso_handle); |
371 | } |
372 | #define LSAN_MAYBE_INTERCEPT___CXA_ATEXIT INTERCEPT_FUNCTION(__cxa_atexit) |
373 | #else |
374 | #define LSAN_MAYBE_INTERCEPT___CXA_ATEXIT |
375 | #endif |
376 | |
377 | #if SANITIZER_INTERCEPT_ATEXIT |
378 | INTERCEPTOR(int, atexit, void (*f)()) { |
379 | __lsan::ScopedInterceptorDisabler disabler; |
380 | return REAL(__cxa_atexit)((void (*)(void *a))f, 0, 0); |
381 | } |
382 | #define LSAN_MAYBE_INTERCEPT_ATEXIT INTERCEPT_FUNCTION(atexit) |
383 | #else |
384 | #define LSAN_MAYBE_INTERCEPT_ATEXIT |
385 | #endif |
386 | |
387 | #if SANITIZER_INTERCEPT_PTHREAD_ATFORK |
388 | extern "C" { |
389 | extern int _pthread_atfork(void (*prepare)(), void (*parent)(), |
390 | void (*child)()); |
391 | } |
392 | |
393 | INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(), |
394 | void (*child)()) { |
395 | __lsan::ScopedInterceptorDisabler disabler; |
396 | // REAL(pthread_atfork) cannot be called due to symbol indirections at least |
397 | // on NetBSD |
398 | return _pthread_atfork(prepare, parent, child); |
399 | } |
400 | #define LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK INTERCEPT_FUNCTION(pthread_atfork) |
401 | #else |
402 | #define LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK |
403 | #endif |
404 | |
405 | #if SANITIZER_INTERCEPT_STRERROR |
406 | INTERCEPTOR(char *, strerror, int errnum) { |
407 | __lsan::ScopedInterceptorDisabler disabler; |
408 | return REAL(strerror)(errnum); |
409 | } |
410 | #define LSAN_MAYBE_INTERCEPT_STRERROR INTERCEPT_FUNCTION(strerror) |
411 | #else |
412 | #define LSAN_MAYBE_INTERCEPT_STRERROR |
413 | #endif |
414 | |
415 | #if SANITIZER_POSIX |
416 | |
417 | template <bool Detached> |
418 | static void *ThreadStartFunc(void *arg) { |
419 | u32 parent_tid = (uptr)arg; |
420 | uptr tid = ThreadCreate(tid: parent_tid, detached: Detached); |
421 | // Wait until the last iteration to maximize the chance that we are the last |
422 | // destructor to run. |
423 | #if !SANITIZER_NETBSD && !SANITIZER_FREEBSD |
424 | if (pthread_setspecific(key: g_thread_finalize_key, |
425 | v: (void*)GetPthreadDestructorIterations())) { |
426 | Report(format: "LeakSanitizer: failed to set thread key.\n" ); |
427 | Die(); |
428 | } |
429 | # endif |
430 | ThreadStart(tid, os_id: GetTid()); |
431 | auto self = GetThreadSelf(); |
432 | auto args = GetThreadArgRetval().GetArgs(thread: self); |
433 | void *retval = (*args.routine)(args.arg_retval); |
434 | GetThreadArgRetval().Finish(thread: self, retval); |
435 | return retval; |
436 | } |
437 | |
438 | INTERCEPTOR(int, pthread_create, void *th, void *attr, |
439 | void *(*callback)(void *), void *param) { |
440 | ENSURE_LSAN_INITED; |
441 | EnsureMainThreadIDIsCorrect(); |
442 | |
443 | bool detached = [attr]() { |
444 | int d = 0; |
445 | return attr && !pthread_attr_getdetachstate(attr, v: &d) && IsStateDetached(state: d); |
446 | }(); |
447 | |
448 | __sanitizer_pthread_attr_t myattr; |
449 | if (!attr) { |
450 | pthread_attr_init(attr: &myattr); |
451 | attr = &myattr; |
452 | } |
453 | AdjustStackSize(attr); |
454 | uptr this_tid = GetCurrentThreadId(); |
455 | int result; |
456 | { |
457 | // Ignore all allocations made by pthread_create: thread stack/TLS may be |
458 | // stored by pthread for future reuse even after thread destruction, and |
459 | // the linked list it's stored in doesn't even hold valid pointers to the |
460 | // objects, the latter are calculated by obscure pointer arithmetic. |
461 | ScopedInterceptorDisabler disabler; |
462 | GetThreadArgRetval().Create(detached, args: {.routine: callback, .arg_retval: param}, fn: [&]() -> uptr { |
463 | result = REAL(pthread_create)( |
464 | th, attr, detached ? ThreadStartFunc<true> : ThreadStartFunc<false>, |
465 | (void *)this_tid); |
466 | return result ? 0 : *(uptr *)(th); |
467 | }); |
468 | } |
469 | if (attr == &myattr) |
470 | pthread_attr_destroy(attr: &myattr); |
471 | return result; |
472 | } |
473 | |
474 | INTERCEPTOR(int, pthread_join, void *thread, void **retval) { |
475 | int result; |
476 | GetThreadArgRetval().Join(thread: (uptr)thread, fn: [&]() { |
477 | result = REAL(pthread_join)(thread, retval); |
478 | return !result; |
479 | }); |
480 | return result; |
481 | } |
482 | |
483 | INTERCEPTOR(int, pthread_detach, void *thread) { |
484 | int result; |
485 | GetThreadArgRetval().Detach(thread: (uptr)thread, fn: [&]() { |
486 | result = REAL(pthread_detach)(thread); |
487 | return !result; |
488 | }); |
489 | return result; |
490 | } |
491 | |
492 | INTERCEPTOR(void, pthread_exit, void *retval) { |
493 | GetThreadArgRetval().Finish(thread: GetThreadSelf(), retval); |
494 | REAL(pthread_exit)(retval); |
495 | } |
496 | |
497 | # if SANITIZER_INTERCEPT_TRYJOIN |
498 | INTERCEPTOR(int, pthread_tryjoin_np, void *thread, void **ret) { |
499 | int result; |
500 | GetThreadArgRetval().Join(thread: (uptr)thread, fn: [&]() { |
501 | result = REAL(pthread_tryjoin_np)(thread, ret); |
502 | return !result; |
503 | }); |
504 | return result; |
505 | } |
506 | # define LSAN_MAYBE_INTERCEPT_TRYJOIN INTERCEPT_FUNCTION(pthread_tryjoin_np) |
507 | # else |
508 | # define LSAN_MAYBE_INTERCEPT_TRYJOIN |
509 | # endif // SANITIZER_INTERCEPT_TRYJOIN |
510 | |
511 | # if SANITIZER_INTERCEPT_TIMEDJOIN |
512 | INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **ret, |
513 | const struct timespec *abstime) { |
514 | int result; |
515 | GetThreadArgRetval().Join(thread: (uptr)thread, fn: [&]() { |
516 | result = REAL(pthread_timedjoin_np)(thread, ret, abstime); |
517 | return !result; |
518 | }); |
519 | return result; |
520 | } |
521 | # define LSAN_MAYBE_INTERCEPT_TIMEDJOIN \ |
522 | INTERCEPT_FUNCTION(pthread_timedjoin_np) |
523 | # else |
524 | # define LSAN_MAYBE_INTERCEPT_TIMEDJOIN |
525 | # endif // SANITIZER_INTERCEPT_TIMEDJOIN |
526 | |
527 | DEFINE_INTERNAL_PTHREAD_FUNCTIONS |
528 | |
529 | INTERCEPTOR(void, _exit, int status) { |
530 | if (status == 0 && HasReportedLeaks()) status = common_flags()->exitcode; |
531 | REAL(_exit)(status); |
532 | } |
533 | |
534 | #define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name) |
535 | #define SIGNAL_INTERCEPTOR_ENTER() ENSURE_LSAN_INITED |
536 | #include "sanitizer_common/sanitizer_signal_interceptors.inc" |
537 | |
538 | #endif // SANITIZER_POSIX |
539 | |
540 | namespace __lsan { |
541 | |
542 | void InitializeInterceptors() { |
543 | // Fuchsia doesn't use interceptors that require any setup. |
544 | #if !SANITIZER_FUCHSIA |
545 | __interception::DoesNotSupportStaticLinking(); |
546 | InitializeSignalInterceptors(); |
547 | |
548 | INTERCEPT_FUNCTION(malloc); |
549 | INTERCEPT_FUNCTION(free); |
550 | LSAN_MAYBE_INTERCEPT_CFREE; |
551 | INTERCEPT_FUNCTION(calloc); |
552 | INTERCEPT_FUNCTION(realloc); |
553 | LSAN_MAYBE_INTERCEPT_MEMALIGN; |
554 | LSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN; |
555 | LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC; |
556 | INTERCEPT_FUNCTION(posix_memalign); |
557 | INTERCEPT_FUNCTION(valloc); |
558 | LSAN_MAYBE_INTERCEPT_PVALLOC; |
559 | LSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE; |
560 | LSAN_MAYBE_INTERCEPT_MALLINFO; |
561 | LSAN_MAYBE_INTERCEPT_MALLOPT; |
562 | INTERCEPT_FUNCTION(pthread_create); |
563 | INTERCEPT_FUNCTION(pthread_join); |
564 | INTERCEPT_FUNCTION(pthread_detach); |
565 | INTERCEPT_FUNCTION(pthread_exit); |
566 | LSAN_MAYBE_INTERCEPT_TIMEDJOIN; |
567 | LSAN_MAYBE_INTERCEPT_TRYJOIN; |
568 | INTERCEPT_FUNCTION(_exit); |
569 | |
570 | LSAN_MAYBE_INTERCEPT__LWP_EXIT; |
571 | LSAN_MAYBE_INTERCEPT_THR_EXIT; |
572 | |
573 | LSAN_MAYBE_INTERCEPT___CXA_ATEXIT; |
574 | LSAN_MAYBE_INTERCEPT_ATEXIT; |
575 | LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK; |
576 | |
577 | LSAN_MAYBE_INTERCEPT_STRERROR; |
578 | |
579 | #if !SANITIZER_NETBSD && !SANITIZER_FREEBSD |
580 | if (pthread_key_create(key: &g_thread_finalize_key, destructor: &thread_finalize)) { |
581 | Report(format: "LeakSanitizer: failed to create thread key.\n" ); |
582 | Die(); |
583 | } |
584 | #endif |
585 | |
586 | #endif // !SANITIZER_FUCHSIA |
587 | } |
588 | |
589 | } // namespace __lsan |
590 | |