xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/lsan/lsan_interceptors.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
168d75effSDimitry Andric //=-- lsan_interceptors.cpp -----------------------------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // This file is a part of LeakSanitizer.
1068d75effSDimitry Andric // Interceptors for standalone LSan.
1168d75effSDimitry Andric //
1268d75effSDimitry Andric //===----------------------------------------------------------------------===//
1368d75effSDimitry Andric 
1468d75effSDimitry Andric #include "interception/interception.h"
1568d75effSDimitry Andric #include "sanitizer_common/sanitizer_allocator.h"
1668d75effSDimitry Andric #include "sanitizer_common/sanitizer_allocator_report.h"
1768d75effSDimitry Andric #include "sanitizer_common/sanitizer_atomic.h"
1868d75effSDimitry Andric #include "sanitizer_common/sanitizer_common.h"
1968d75effSDimitry Andric #include "sanitizer_common/sanitizer_flags.h"
2068d75effSDimitry Andric #include "sanitizer_common/sanitizer_internal_defs.h"
2168d75effSDimitry Andric #include "sanitizer_common/sanitizer_linux.h"
2268d75effSDimitry Andric #include "sanitizer_common/sanitizer_platform_interceptors.h"
2368d75effSDimitry Andric #include "sanitizer_common/sanitizer_platform_limits_netbsd.h"
2468d75effSDimitry Andric #include "sanitizer_common/sanitizer_platform_limits_posix.h"
25*5ffd83dbSDimitry Andric #if SANITIZER_POSIX
2668d75effSDimitry Andric #include "sanitizer_common/sanitizer_posix.h"
27*5ffd83dbSDimitry Andric #endif
2868d75effSDimitry Andric #include "sanitizer_common/sanitizer_tls_get_addr.h"
2968d75effSDimitry Andric #include "lsan.h"
3068d75effSDimitry Andric #include "lsan_allocator.h"
3168d75effSDimitry Andric #include "lsan_common.h"
3268d75effSDimitry Andric #include "lsan_thread.h"
3368d75effSDimitry Andric 
3468d75effSDimitry Andric #include <stddef.h>
3568d75effSDimitry Andric 
3668d75effSDimitry Andric using namespace __lsan;
3768d75effSDimitry Andric 
3868d75effSDimitry Andric extern "C" {
3968d75effSDimitry Andric int pthread_attr_init(void *attr);
4068d75effSDimitry Andric int pthread_attr_destroy(void *attr);
4168d75effSDimitry Andric int pthread_attr_getdetachstate(void *attr, int *v);
4268d75effSDimitry Andric int pthread_key_create(unsigned *key, void (*destructor)(void* v));
4368d75effSDimitry Andric int pthread_setspecific(unsigned key, const void *v);
4468d75effSDimitry Andric }
4568d75effSDimitry Andric 
4668d75effSDimitry Andric ///// Malloc/free interceptors. /////
4768d75effSDimitry Andric 
4868d75effSDimitry Andric namespace std {
4968d75effSDimitry Andric   struct nothrow_t;
5068d75effSDimitry Andric   enum class align_val_t: size_t;
5168d75effSDimitry Andric }
5268d75effSDimitry Andric 
5368d75effSDimitry Andric #if !SANITIZER_MAC
5468d75effSDimitry Andric INTERCEPTOR(void*, malloc, uptr size) {
5568d75effSDimitry Andric   ENSURE_LSAN_INITED;
5668d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;
5768d75effSDimitry Andric   return lsan_malloc(size, stack);
5868d75effSDimitry Andric }
5968d75effSDimitry Andric 
6068d75effSDimitry Andric INTERCEPTOR(void, free, void *p) {
6168d75effSDimitry Andric   ENSURE_LSAN_INITED;
6268d75effSDimitry Andric   lsan_free(p);
6368d75effSDimitry Andric }
6468d75effSDimitry Andric 
6568d75effSDimitry Andric INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
66*5ffd83dbSDimitry Andric   // This hack is not required for Fuchsia because there are no dlsym calls
67*5ffd83dbSDimitry Andric   // involved in setting up interceptors.
68*5ffd83dbSDimitry Andric #if !SANITIZER_FUCHSIA
6968d75effSDimitry Andric   if (lsan_init_is_running) {
7068d75effSDimitry Andric     // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
7168d75effSDimitry Andric     const uptr kCallocPoolSize = 1024;
7268d75effSDimitry Andric     static uptr calloc_memory_for_dlsym[kCallocPoolSize];
7368d75effSDimitry Andric     static uptr allocated;
7468d75effSDimitry Andric     uptr size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize;
7568d75effSDimitry Andric     void *mem = (void*)&calloc_memory_for_dlsym[allocated];
7668d75effSDimitry Andric     allocated += size_in_words;
7768d75effSDimitry Andric     CHECK(allocated < kCallocPoolSize);
7868d75effSDimitry Andric     return mem;
7968d75effSDimitry Andric   }
80*5ffd83dbSDimitry Andric #endif  // !SANITIZER_FUCHSIA
8168d75effSDimitry Andric   ENSURE_LSAN_INITED;
8268d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;
8368d75effSDimitry Andric   return lsan_calloc(nmemb, size, stack);
8468d75effSDimitry Andric }
8568d75effSDimitry Andric 
8668d75effSDimitry Andric INTERCEPTOR(void*, realloc, void *q, uptr size) {
8768d75effSDimitry Andric   ENSURE_LSAN_INITED;
8868d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;
8968d75effSDimitry Andric   return lsan_realloc(q, size, stack);
9068d75effSDimitry Andric }
9168d75effSDimitry Andric 
9268d75effSDimitry Andric INTERCEPTOR(void*, reallocarray, void *q, uptr nmemb, uptr size) {
9368d75effSDimitry Andric   ENSURE_LSAN_INITED;
9468d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;
9568d75effSDimitry Andric   return lsan_reallocarray(q, nmemb, size, stack);
9668d75effSDimitry Andric }
9768d75effSDimitry Andric 
9868d75effSDimitry Andric INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
9968d75effSDimitry Andric   ENSURE_LSAN_INITED;
10068d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;
10168d75effSDimitry Andric   return lsan_posix_memalign(memptr, alignment, size, stack);
10268d75effSDimitry Andric }
10368d75effSDimitry Andric 
10468d75effSDimitry Andric INTERCEPTOR(void*, valloc, uptr size) {
10568d75effSDimitry Andric   ENSURE_LSAN_INITED;
10668d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;
10768d75effSDimitry Andric   return lsan_valloc(size, stack);
10868d75effSDimitry Andric }
109*5ffd83dbSDimitry Andric #endif  // !SANITIZER_MAC
11068d75effSDimitry Andric 
11168d75effSDimitry Andric #if SANITIZER_INTERCEPT_MEMALIGN
11268d75effSDimitry Andric INTERCEPTOR(void*, memalign, uptr alignment, uptr size) {
11368d75effSDimitry Andric   ENSURE_LSAN_INITED;
11468d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;
11568d75effSDimitry Andric   return lsan_memalign(alignment, size, stack);
11668d75effSDimitry Andric }
11768d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_MEMALIGN INTERCEPT_FUNCTION(memalign)
11868d75effSDimitry Andric 
11968d75effSDimitry Andric INTERCEPTOR(void *, __libc_memalign, uptr alignment, uptr size) {
12068d75effSDimitry Andric   ENSURE_LSAN_INITED;
12168d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;
12268d75effSDimitry Andric   void *res = lsan_memalign(alignment, size, stack);
12368d75effSDimitry Andric   DTLS_on_libc_memalign(res, size);
12468d75effSDimitry Andric   return res;
12568d75effSDimitry Andric }
12668d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN INTERCEPT_FUNCTION(__libc_memalign)
12768d75effSDimitry Andric #else
12868d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_MEMALIGN
12968d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN
13068d75effSDimitry Andric #endif // SANITIZER_INTERCEPT_MEMALIGN
13168d75effSDimitry Andric 
13268d75effSDimitry Andric #if SANITIZER_INTERCEPT_ALIGNED_ALLOC
13368d75effSDimitry Andric INTERCEPTOR(void*, aligned_alloc, uptr alignment, uptr size) {
13468d75effSDimitry Andric   ENSURE_LSAN_INITED;
13568d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;
13668d75effSDimitry Andric   return lsan_aligned_alloc(alignment, size, stack);
13768d75effSDimitry Andric }
13868d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC INTERCEPT_FUNCTION(aligned_alloc)
13968d75effSDimitry Andric #else
14068d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC
14168d75effSDimitry Andric #endif
14268d75effSDimitry Andric 
14368d75effSDimitry Andric #if SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE
14468d75effSDimitry Andric INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
14568d75effSDimitry Andric   ENSURE_LSAN_INITED;
14668d75effSDimitry Andric   return GetMallocUsableSize(ptr);
14768d75effSDimitry Andric }
14868d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE \
14968d75effSDimitry Andric         INTERCEPT_FUNCTION(malloc_usable_size)
15068d75effSDimitry Andric #else
15168d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE
15268d75effSDimitry Andric #endif
15368d75effSDimitry Andric 
15468d75effSDimitry Andric #if SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO
15568d75effSDimitry Andric struct fake_mallinfo {
15668d75effSDimitry Andric   int x[10];
15768d75effSDimitry Andric };
15868d75effSDimitry Andric 
15968d75effSDimitry Andric INTERCEPTOR(struct fake_mallinfo, mallinfo, void) {
16068d75effSDimitry Andric   struct fake_mallinfo res;
16168d75effSDimitry Andric   internal_memset(&res, 0, sizeof(res));
16268d75effSDimitry Andric   return res;
16368d75effSDimitry Andric }
16468d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_MALLINFO INTERCEPT_FUNCTION(mallinfo)
16568d75effSDimitry Andric 
16668d75effSDimitry Andric INTERCEPTOR(int, mallopt, int cmd, int value) {
16768d75effSDimitry Andric   return 0;
16868d75effSDimitry Andric }
16968d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_MALLOPT INTERCEPT_FUNCTION(mallopt)
17068d75effSDimitry Andric #else
17168d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_MALLINFO
17268d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_MALLOPT
17368d75effSDimitry Andric #endif // SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO
17468d75effSDimitry Andric 
17568d75effSDimitry Andric #if SANITIZER_INTERCEPT_PVALLOC
17668d75effSDimitry Andric INTERCEPTOR(void*, pvalloc, uptr size) {
17768d75effSDimitry Andric   ENSURE_LSAN_INITED;
17868d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;
17968d75effSDimitry Andric   return lsan_pvalloc(size, stack);
18068d75effSDimitry Andric }
18168d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_PVALLOC INTERCEPT_FUNCTION(pvalloc)
18268d75effSDimitry Andric #else
18368d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_PVALLOC
18468d75effSDimitry Andric #endif // SANITIZER_INTERCEPT_PVALLOC
18568d75effSDimitry Andric 
18668d75effSDimitry Andric #if SANITIZER_INTERCEPT_CFREE
18768d75effSDimitry Andric INTERCEPTOR(void, cfree, void *p) ALIAS(WRAPPER_NAME(free));
18868d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_CFREE INTERCEPT_FUNCTION(cfree)
18968d75effSDimitry Andric #else
19068d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_CFREE
19168d75effSDimitry Andric #endif // SANITIZER_INTERCEPT_CFREE
19268d75effSDimitry Andric 
19368d75effSDimitry Andric #if SANITIZER_INTERCEPT_MCHECK_MPROBE
19468d75effSDimitry Andric INTERCEPTOR(int, mcheck, void (*abortfunc)(int mstatus)) {
19568d75effSDimitry Andric   return 0;
19668d75effSDimitry Andric }
19768d75effSDimitry Andric 
19868d75effSDimitry Andric INTERCEPTOR(int, mcheck_pedantic, void (*abortfunc)(int mstatus)) {
19968d75effSDimitry Andric   return 0;
20068d75effSDimitry Andric }
20168d75effSDimitry Andric 
20268d75effSDimitry Andric INTERCEPTOR(int, mprobe, void *ptr) {
20368d75effSDimitry Andric   return 0;
20468d75effSDimitry Andric }
20568d75effSDimitry Andric #endif // SANITIZER_INTERCEPT_MCHECK_MPROBE
20668d75effSDimitry Andric 
20768d75effSDimitry Andric 
20868d75effSDimitry Andric // TODO(alekseys): throw std::bad_alloc instead of dying on OOM.
20968d75effSDimitry Andric #define OPERATOR_NEW_BODY(nothrow)\
21068d75effSDimitry Andric   ENSURE_LSAN_INITED;\
21168d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;\
21268d75effSDimitry Andric   void *res = lsan_malloc(size, stack);\
21368d75effSDimitry Andric   if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\
21468d75effSDimitry Andric   return res;
21568d75effSDimitry Andric #define OPERATOR_NEW_BODY_ALIGN(nothrow)\
21668d75effSDimitry Andric   ENSURE_LSAN_INITED;\
21768d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;\
21868d75effSDimitry Andric   void *res = lsan_memalign((uptr)align, size, stack);\
21968d75effSDimitry Andric   if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\
22068d75effSDimitry Andric   return res;
22168d75effSDimitry Andric 
22268d75effSDimitry Andric #define OPERATOR_DELETE_BODY\
22368d75effSDimitry Andric   ENSURE_LSAN_INITED;\
22468d75effSDimitry Andric   lsan_free(ptr);
22568d75effSDimitry Andric 
22668d75effSDimitry Andric // On OS X it's not enough to just provide our own 'operator new' and
22768d75effSDimitry Andric // 'operator delete' implementations, because they're going to be in the runtime
22868d75effSDimitry Andric // dylib, and the main executable will depend on both the runtime dylib and
22968d75effSDimitry Andric // libstdc++, each of has its implementation of new and delete.
23068d75effSDimitry Andric // To make sure that C++ allocation/deallocation operators are overridden on
23168d75effSDimitry Andric // OS X we need to intercept them using their mangled names.
23268d75effSDimitry Andric #if !SANITIZER_MAC
23368d75effSDimitry Andric 
23468d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
23568d75effSDimitry Andric void *operator new(size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); }
23668d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
23768d75effSDimitry Andric void *operator new[](size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); }
23868d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
23968d75effSDimitry Andric void *operator new(size_t size, std::nothrow_t const&)
24068d75effSDimitry Andric { OPERATOR_NEW_BODY(true /*nothrow*/); }
24168d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
24268d75effSDimitry Andric void *operator new[](size_t size, std::nothrow_t const&)
24368d75effSDimitry Andric { OPERATOR_NEW_BODY(true /*nothrow*/); }
24468d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
24568d75effSDimitry Andric void *operator new(size_t size, std::align_val_t align)
24668d75effSDimitry Andric { OPERATOR_NEW_BODY_ALIGN(false /*nothrow*/); }
24768d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
24868d75effSDimitry Andric void *operator new[](size_t size, std::align_val_t align)
24968d75effSDimitry Andric { OPERATOR_NEW_BODY_ALIGN(false /*nothrow*/); }
25068d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
25168d75effSDimitry Andric void *operator new(size_t size, std::align_val_t align, std::nothrow_t const&)
25268d75effSDimitry Andric { OPERATOR_NEW_BODY_ALIGN(true /*nothrow*/); }
25368d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
25468d75effSDimitry Andric void *operator new[](size_t size, std::align_val_t align, std::nothrow_t const&)
25568d75effSDimitry Andric { OPERATOR_NEW_BODY_ALIGN(true /*nothrow*/); }
25668d75effSDimitry Andric 
25768d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
25868d75effSDimitry Andric void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
25968d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
26068d75effSDimitry Andric void operator delete[](void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
26168d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
26268d75effSDimitry Andric void operator delete(void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY; }
26368d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
26468d75effSDimitry Andric void operator delete[](void *ptr, std::nothrow_t const &)
26568d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
26668d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
26768d75effSDimitry Andric void operator delete(void *ptr, size_t size) NOEXCEPT
26868d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
26968d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
27068d75effSDimitry Andric void operator delete[](void *ptr, size_t size) NOEXCEPT
27168d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
27268d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
27368d75effSDimitry Andric void operator delete(void *ptr, std::align_val_t) NOEXCEPT
27468d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
27568d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
27668d75effSDimitry Andric void operator delete[](void *ptr, std::align_val_t) NOEXCEPT
27768d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
27868d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
27968d75effSDimitry Andric void operator delete(void *ptr, std::align_val_t, std::nothrow_t const&)
28068d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
28168d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
28268d75effSDimitry Andric void operator delete[](void *ptr, std::align_val_t, std::nothrow_t const&)
28368d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
28468d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
28568d75effSDimitry Andric void operator delete(void *ptr, size_t size, std::align_val_t) NOEXCEPT
28668d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
28768d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
28868d75effSDimitry Andric void operator delete[](void *ptr, size_t size, std::align_val_t) NOEXCEPT
28968d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
29068d75effSDimitry Andric 
29168d75effSDimitry Andric #else  // SANITIZER_MAC
29268d75effSDimitry Andric 
29368d75effSDimitry Andric INTERCEPTOR(void *, _Znwm, size_t size)
29468d75effSDimitry Andric { OPERATOR_NEW_BODY(false /*nothrow*/); }
29568d75effSDimitry Andric INTERCEPTOR(void *, _Znam, size_t size)
29668d75effSDimitry Andric { OPERATOR_NEW_BODY(false /*nothrow*/); }
29768d75effSDimitry Andric INTERCEPTOR(void *, _ZnwmRKSt9nothrow_t, size_t size, std::nothrow_t const&)
29868d75effSDimitry Andric { OPERATOR_NEW_BODY(true /*nothrow*/); }
29968d75effSDimitry Andric INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&)
30068d75effSDimitry Andric { OPERATOR_NEW_BODY(true /*nothrow*/); }
30168d75effSDimitry Andric 
30268d75effSDimitry Andric INTERCEPTOR(void, _ZdlPv, void *ptr)
30368d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
30468d75effSDimitry Andric INTERCEPTOR(void, _ZdaPv, void *ptr)
30568d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
30668d75effSDimitry Andric INTERCEPTOR(void, _ZdlPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&)
30768d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
30868d75effSDimitry Andric INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&)
30968d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
31068d75effSDimitry Andric 
31168d75effSDimitry Andric #endif  // !SANITIZER_MAC
31268d75effSDimitry Andric 
31368d75effSDimitry Andric 
31468d75effSDimitry Andric ///// Thread initialization and finalization. /////
31568d75effSDimitry Andric 
316*5ffd83dbSDimitry Andric #if !SANITIZER_NETBSD && !SANITIZER_FREEBSD && !SANITIZER_FUCHSIA
31768d75effSDimitry Andric static unsigned g_thread_finalize_key;
31868d75effSDimitry Andric 
31968d75effSDimitry Andric static void thread_finalize(void *v) {
32068d75effSDimitry Andric   uptr iter = (uptr)v;
32168d75effSDimitry Andric   if (iter > 1) {
32268d75effSDimitry Andric     if (pthread_setspecific(g_thread_finalize_key, (void*)(iter - 1))) {
32368d75effSDimitry Andric       Report("LeakSanitizer: failed to set thread key.\n");
32468d75effSDimitry Andric       Die();
32568d75effSDimitry Andric     }
32668d75effSDimitry Andric     return;
32768d75effSDimitry Andric   }
32868d75effSDimitry Andric   ThreadFinish();
32968d75effSDimitry Andric }
33068d75effSDimitry Andric #endif
33168d75effSDimitry Andric 
33268d75effSDimitry Andric #if SANITIZER_NETBSD
33368d75effSDimitry Andric INTERCEPTOR(void, _lwp_exit) {
33468d75effSDimitry Andric   ENSURE_LSAN_INITED;
33568d75effSDimitry Andric   ThreadFinish();
33668d75effSDimitry Andric   REAL(_lwp_exit)();
33768d75effSDimitry Andric }
33868d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT__LWP_EXIT INTERCEPT_FUNCTION(_lwp_exit)
33968d75effSDimitry Andric #else
34068d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT__LWP_EXIT
34168d75effSDimitry Andric #endif
34268d75effSDimitry Andric 
34368d75effSDimitry Andric #if SANITIZER_INTERCEPT_THR_EXIT
34468d75effSDimitry Andric INTERCEPTOR(void, thr_exit, tid_t *state) {
34568d75effSDimitry Andric   ENSURE_LSAN_INITED;
34668d75effSDimitry Andric   ThreadFinish();
34768d75effSDimitry Andric   REAL(thr_exit)(state);
34868d75effSDimitry Andric }
34968d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_THR_EXIT INTERCEPT_FUNCTION(thr_exit)
35068d75effSDimitry Andric #else
35168d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_THR_EXIT
35268d75effSDimitry Andric #endif
35368d75effSDimitry Andric 
35468d75effSDimitry Andric #if SANITIZER_INTERCEPT___CXA_ATEXIT
35568d75effSDimitry Andric INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
35668d75effSDimitry Andric             void *dso_handle) {
35768d75effSDimitry Andric   __lsan::ScopedInterceptorDisabler disabler;
35868d75effSDimitry Andric   return REAL(__cxa_atexit)(func, arg, dso_handle);
35968d75effSDimitry Andric }
36068d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT___CXA_ATEXIT INTERCEPT_FUNCTION(__cxa_atexit)
36168d75effSDimitry Andric #else
36268d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT___CXA_ATEXIT
36368d75effSDimitry Andric #endif
36468d75effSDimitry Andric 
36568d75effSDimitry Andric #if SANITIZER_INTERCEPT_ATEXIT
36668d75effSDimitry Andric INTERCEPTOR(int, atexit, void (*f)()) {
36768d75effSDimitry Andric   __lsan::ScopedInterceptorDisabler disabler;
36868d75effSDimitry Andric   return REAL(__cxa_atexit)((void (*)(void *a))f, 0, 0);
36968d75effSDimitry Andric }
37068d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_ATEXIT INTERCEPT_FUNCTION(atexit)
37168d75effSDimitry Andric #else
37268d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_ATEXIT
37368d75effSDimitry Andric #endif
37468d75effSDimitry Andric 
37568d75effSDimitry Andric #if SANITIZER_INTERCEPT_PTHREAD_ATFORK
37668d75effSDimitry Andric extern "C" {
37768d75effSDimitry Andric extern int _pthread_atfork(void (*prepare)(), void (*parent)(),
37868d75effSDimitry Andric                            void (*child)());
37968d75effSDimitry Andric };
38068d75effSDimitry Andric 
38168d75effSDimitry Andric INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(),
38268d75effSDimitry Andric             void (*child)()) {
38368d75effSDimitry Andric   __lsan::ScopedInterceptorDisabler disabler;
38468d75effSDimitry Andric   // REAL(pthread_atfork) cannot be called due to symbol indirections at least
38568d75effSDimitry Andric   // on NetBSD
38668d75effSDimitry Andric   return _pthread_atfork(prepare, parent, child);
38768d75effSDimitry Andric }
38868d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK INTERCEPT_FUNCTION(pthread_atfork)
38968d75effSDimitry Andric #else
39068d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK
39168d75effSDimitry Andric #endif
39268d75effSDimitry Andric 
39368d75effSDimitry Andric #if SANITIZER_INTERCEPT_STRERROR
39468d75effSDimitry Andric INTERCEPTOR(char *, strerror, int errnum) {
39568d75effSDimitry Andric   __lsan::ScopedInterceptorDisabler disabler;
39668d75effSDimitry Andric   return REAL(strerror)(errnum);
39768d75effSDimitry Andric }
39868d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_STRERROR INTERCEPT_FUNCTION(strerror)
39968d75effSDimitry Andric #else
40068d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_STRERROR
40168d75effSDimitry Andric #endif
40268d75effSDimitry Andric 
403*5ffd83dbSDimitry Andric #if SANITIZER_POSIX
404*5ffd83dbSDimitry Andric 
40568d75effSDimitry Andric struct ThreadParam {
40668d75effSDimitry Andric   void *(*callback)(void *arg);
40768d75effSDimitry Andric   void *param;
40868d75effSDimitry Andric   atomic_uintptr_t tid;
40968d75effSDimitry Andric };
41068d75effSDimitry Andric 
41168d75effSDimitry Andric extern "C" void *__lsan_thread_start_func(void *arg) {
41268d75effSDimitry Andric   ThreadParam *p = (ThreadParam*)arg;
41368d75effSDimitry Andric   void* (*callback)(void *arg) = p->callback;
41468d75effSDimitry Andric   void *param = p->param;
41568d75effSDimitry Andric   // Wait until the last iteration to maximize the chance that we are the last
41668d75effSDimitry Andric   // destructor to run.
41768d75effSDimitry Andric #if !SANITIZER_NETBSD && !SANITIZER_FREEBSD
41868d75effSDimitry Andric   if (pthread_setspecific(g_thread_finalize_key,
41968d75effSDimitry Andric                           (void*)GetPthreadDestructorIterations())) {
42068d75effSDimitry Andric     Report("LeakSanitizer: failed to set thread key.\n");
42168d75effSDimitry Andric     Die();
42268d75effSDimitry Andric   }
42368d75effSDimitry Andric #endif
42468d75effSDimitry Andric   int tid = 0;
42568d75effSDimitry Andric   while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0)
42668d75effSDimitry Andric     internal_sched_yield();
42768d75effSDimitry Andric   ThreadStart(tid, GetTid());
42868d75effSDimitry Andric   atomic_store(&p->tid, 0, memory_order_release);
42968d75effSDimitry Andric   return callback(param);
43068d75effSDimitry Andric }
43168d75effSDimitry Andric 
43268d75effSDimitry Andric INTERCEPTOR(int, pthread_create, void *th, void *attr,
43368d75effSDimitry Andric             void *(*callback)(void *), void *param) {
43468d75effSDimitry Andric   ENSURE_LSAN_INITED;
43568d75effSDimitry Andric   EnsureMainThreadIDIsCorrect();
43668d75effSDimitry Andric   __sanitizer_pthread_attr_t myattr;
43768d75effSDimitry Andric   if (!attr) {
43868d75effSDimitry Andric     pthread_attr_init(&myattr);
43968d75effSDimitry Andric     attr = &myattr;
44068d75effSDimitry Andric   }
44168d75effSDimitry Andric   AdjustStackSize(attr);
44268d75effSDimitry Andric   int detached = 0;
44368d75effSDimitry Andric   pthread_attr_getdetachstate(attr, &detached);
44468d75effSDimitry Andric   ThreadParam p;
44568d75effSDimitry Andric   p.callback = callback;
44668d75effSDimitry Andric   p.param = param;
44768d75effSDimitry Andric   atomic_store(&p.tid, 0, memory_order_relaxed);
44868d75effSDimitry Andric   int res;
44968d75effSDimitry Andric   {
45068d75effSDimitry Andric     // Ignore all allocations made by pthread_create: thread stack/TLS may be
45168d75effSDimitry Andric     // stored by pthread for future reuse even after thread destruction, and
45268d75effSDimitry Andric     // the linked list it's stored in doesn't even hold valid pointers to the
45368d75effSDimitry Andric     // objects, the latter are calculated by obscure pointer arithmetic.
45468d75effSDimitry Andric     ScopedInterceptorDisabler disabler;
45568d75effSDimitry Andric     res = REAL(pthread_create)(th, attr, __lsan_thread_start_func, &p);
45668d75effSDimitry Andric   }
45768d75effSDimitry Andric   if (res == 0) {
45868d75effSDimitry Andric     int tid = ThreadCreate(GetCurrentThread(), *(uptr *)th,
45968d75effSDimitry Andric                            IsStateDetached(detached));
46068d75effSDimitry Andric     CHECK_NE(tid, 0);
46168d75effSDimitry Andric     atomic_store(&p.tid, tid, memory_order_release);
46268d75effSDimitry Andric     while (atomic_load(&p.tid, memory_order_acquire) != 0)
46368d75effSDimitry Andric       internal_sched_yield();
46468d75effSDimitry Andric   }
46568d75effSDimitry Andric   if (attr == &myattr)
46668d75effSDimitry Andric     pthread_attr_destroy(&myattr);
46768d75effSDimitry Andric   return res;
46868d75effSDimitry Andric }
46968d75effSDimitry Andric 
47068d75effSDimitry Andric INTERCEPTOR(int, pthread_join, void *th, void **ret) {
47168d75effSDimitry Andric   ENSURE_LSAN_INITED;
47268d75effSDimitry Andric   int tid = ThreadTid((uptr)th);
47368d75effSDimitry Andric   int res = REAL(pthread_join)(th, ret);
47468d75effSDimitry Andric   if (res == 0)
47568d75effSDimitry Andric     ThreadJoin(tid);
47668d75effSDimitry Andric   return res;
47768d75effSDimitry Andric }
47868d75effSDimitry Andric 
47968d75effSDimitry Andric INTERCEPTOR(void, _exit, int status) {
48068d75effSDimitry Andric   if (status == 0 && HasReportedLeaks()) status = common_flags()->exitcode;
48168d75effSDimitry Andric   REAL(_exit)(status);
48268d75effSDimitry Andric }
48368d75effSDimitry Andric 
48468d75effSDimitry Andric #define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name)
48568d75effSDimitry Andric #include "sanitizer_common/sanitizer_signal_interceptors.inc"
48668d75effSDimitry Andric 
487*5ffd83dbSDimitry Andric #endif  // SANITIZER_POSIX
488*5ffd83dbSDimitry Andric 
48968d75effSDimitry Andric namespace __lsan {
49068d75effSDimitry Andric 
49168d75effSDimitry Andric void InitializeInterceptors() {
492*5ffd83dbSDimitry Andric   // Fuchsia doesn't use interceptors that require any setup.
493*5ffd83dbSDimitry Andric #if !SANITIZER_FUCHSIA
49468d75effSDimitry Andric   InitializeSignalInterceptors();
49568d75effSDimitry Andric 
49668d75effSDimitry Andric   INTERCEPT_FUNCTION(malloc);
49768d75effSDimitry Andric   INTERCEPT_FUNCTION(free);
49868d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_CFREE;
49968d75effSDimitry Andric   INTERCEPT_FUNCTION(calloc);
50068d75effSDimitry Andric   INTERCEPT_FUNCTION(realloc);
50168d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_MEMALIGN;
50268d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN;
50368d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC;
50468d75effSDimitry Andric   INTERCEPT_FUNCTION(posix_memalign);
50568d75effSDimitry Andric   INTERCEPT_FUNCTION(valloc);
50668d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_PVALLOC;
50768d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE;
50868d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_MALLINFO;
50968d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_MALLOPT;
51068d75effSDimitry Andric   INTERCEPT_FUNCTION(pthread_create);
51168d75effSDimitry Andric   INTERCEPT_FUNCTION(pthread_join);
51268d75effSDimitry Andric   INTERCEPT_FUNCTION(_exit);
51368d75effSDimitry Andric 
51468d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT__LWP_EXIT;
51568d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_THR_EXIT;
51668d75effSDimitry Andric 
51768d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT___CXA_ATEXIT;
51868d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_ATEXIT;
51968d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK;
52068d75effSDimitry Andric 
52168d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_STRERROR;
52268d75effSDimitry Andric 
52368d75effSDimitry Andric #if !SANITIZER_NETBSD && !SANITIZER_FREEBSD
52468d75effSDimitry Andric   if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) {
52568d75effSDimitry Andric     Report("LeakSanitizer: failed to create thread key.\n");
52668d75effSDimitry Andric     Die();
52768d75effSDimitry Andric   }
52868d75effSDimitry Andric #endif
529*5ffd83dbSDimitry Andric 
530*5ffd83dbSDimitry Andric #endif  // !SANITIZER_FUCHSIA
53168d75effSDimitry Andric }
53268d75effSDimitry Andric 
53368d75effSDimitry Andric } // namespace __lsan
534