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