xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/lsan/lsan_interceptors.cpp (revision 6c05f3a74f30934ee60919cc97e16ec69b542b06)
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"
16349cc55cSDimitry Andric #include "sanitizer_common/sanitizer_allocator_dlsym.h"
1768d75effSDimitry Andric #include "sanitizer_common/sanitizer_allocator_report.h"
1868d75effSDimitry Andric #include "sanitizer_common/sanitizer_atomic.h"
1968d75effSDimitry Andric #include "sanitizer_common/sanitizer_common.h"
2068d75effSDimitry Andric #include "sanitizer_common/sanitizer_flags.h"
2168d75effSDimitry Andric #include "sanitizer_common/sanitizer_internal_defs.h"
2268d75effSDimitry Andric #include "sanitizer_common/sanitizer_linux.h"
2368d75effSDimitry Andric #include "sanitizer_common/sanitizer_platform_interceptors.h"
2468d75effSDimitry Andric #include "sanitizer_common/sanitizer_platform_limits_netbsd.h"
2568d75effSDimitry Andric #include "sanitizer_common/sanitizer_platform_limits_posix.h"
265ffd83dbSDimitry Andric #if SANITIZER_POSIX
2768d75effSDimitry Andric #include "sanitizer_common/sanitizer_posix.h"
285ffd83dbSDimitry Andric #endif
2968d75effSDimitry Andric #include "sanitizer_common/sanitizer_tls_get_addr.h"
3068d75effSDimitry Andric #include "lsan.h"
3168d75effSDimitry Andric #include "lsan_allocator.h"
3268d75effSDimitry Andric #include "lsan_common.h"
3368d75effSDimitry Andric #include "lsan_thread.h"
3468d75effSDimitry Andric 
3568d75effSDimitry Andric #include <stddef.h>
3668d75effSDimitry Andric 
3768d75effSDimitry Andric using namespace __lsan;
3868d75effSDimitry Andric 
3968d75effSDimitry Andric extern "C" {
4068d75effSDimitry Andric int pthread_attr_init(void *attr);
4168d75effSDimitry Andric int pthread_attr_destroy(void *attr);
4268d75effSDimitry Andric int pthread_attr_getdetachstate(void *attr, int *v);
4368d75effSDimitry Andric int pthread_key_create(unsigned *key, void (*destructor)(void* v));
4468d75effSDimitry Andric int pthread_setspecific(unsigned key, const void *v);
4568d75effSDimitry Andric }
4668d75effSDimitry Andric 
47349cc55cSDimitry Andric struct DlsymAlloc : DlSymAllocator<DlsymAlloc> {
48349cc55cSDimitry Andric   static bool UseImpl() { return lsan_init_is_running; }
49349cc55cSDimitry Andric   static void OnAllocate(const void *ptr, uptr size) {
50349cc55cSDimitry Andric #if CAN_SANITIZE_LEAKS
51349cc55cSDimitry Andric     // Suppress leaks from dlerror(). Previously dlsym hack on global array was
52349cc55cSDimitry Andric     // used by leak sanitizer as a root region.
53349cc55cSDimitry Andric     __lsan_register_root_region(ptr, size);
54349cc55cSDimitry Andric #endif
55349cc55cSDimitry Andric   }
56349cc55cSDimitry Andric   static void OnFree(const void *ptr, uptr size) {
57349cc55cSDimitry Andric #if CAN_SANITIZE_LEAKS
58349cc55cSDimitry Andric     __lsan_unregister_root_region(ptr, size);
59349cc55cSDimitry Andric #endif
60349cc55cSDimitry Andric   }
61349cc55cSDimitry Andric };
62349cc55cSDimitry Andric 
6368d75effSDimitry Andric ///// Malloc/free interceptors. /////
6468d75effSDimitry Andric 
6568d75effSDimitry Andric namespace std {
6668d75effSDimitry Andric   struct nothrow_t;
6768d75effSDimitry Andric   enum class align_val_t: size_t;
6868d75effSDimitry Andric }
6968d75effSDimitry Andric 
7081ad6265SDimitry Andric #if !SANITIZER_APPLE
7168d75effSDimitry Andric INTERCEPTOR(void*, malloc, uptr size) {
72349cc55cSDimitry Andric   if (DlsymAlloc::Use())
73349cc55cSDimitry Andric     return DlsymAlloc::Allocate(size);
7468d75effSDimitry Andric   ENSURE_LSAN_INITED;
7568d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;
7668d75effSDimitry Andric   return lsan_malloc(size, stack);
7768d75effSDimitry Andric }
7868d75effSDimitry Andric 
7968d75effSDimitry Andric INTERCEPTOR(void, free, void *p) {
80*6c05f3a7SDimitry Andric   if (UNLIKELY(!p))
81*6c05f3a7SDimitry Andric     return;
82349cc55cSDimitry Andric   if (DlsymAlloc::PointerIsMine(p))
83349cc55cSDimitry Andric     return DlsymAlloc::Free(p);
8468d75effSDimitry Andric   ENSURE_LSAN_INITED;
8568d75effSDimitry Andric   lsan_free(p);
8668d75effSDimitry Andric }
8768d75effSDimitry Andric 
8868d75effSDimitry Andric INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
89349cc55cSDimitry Andric   if (DlsymAlloc::Use())
90349cc55cSDimitry Andric     return DlsymAlloc::Callocate(nmemb, size);
9168d75effSDimitry Andric   ENSURE_LSAN_INITED;
9268d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;
9368d75effSDimitry Andric   return lsan_calloc(nmemb, size, stack);
9468d75effSDimitry Andric }
9568d75effSDimitry Andric 
96349cc55cSDimitry Andric INTERCEPTOR(void *, realloc, void *ptr, uptr size) {
97349cc55cSDimitry Andric   if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr))
98349cc55cSDimitry Andric     return DlsymAlloc::Realloc(ptr, size);
9968d75effSDimitry Andric   ENSURE_LSAN_INITED;
10068d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;
101349cc55cSDimitry Andric   return lsan_realloc(ptr, size, stack);
10268d75effSDimitry Andric }
10368d75effSDimitry Andric 
10468d75effSDimitry Andric INTERCEPTOR(void*, reallocarray, void *q, uptr nmemb, uptr size) {
10568d75effSDimitry Andric   ENSURE_LSAN_INITED;
10668d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;
10768d75effSDimitry Andric   return lsan_reallocarray(q, nmemb, size, stack);
10868d75effSDimitry Andric }
10968d75effSDimitry Andric 
11068d75effSDimitry Andric INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
11168d75effSDimitry Andric   ENSURE_LSAN_INITED;
11268d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;
11368d75effSDimitry Andric   return lsan_posix_memalign(memptr, alignment, size, stack);
11468d75effSDimitry Andric }
11568d75effSDimitry Andric 
11668d75effSDimitry Andric INTERCEPTOR(void*, valloc, uptr size) {
11768d75effSDimitry Andric   ENSURE_LSAN_INITED;
11868d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;
11968d75effSDimitry Andric   return lsan_valloc(size, stack);
12068d75effSDimitry Andric }
12181ad6265SDimitry Andric #endif  // !SANITIZER_APPLE
12268d75effSDimitry Andric 
12368d75effSDimitry Andric #if SANITIZER_INTERCEPT_MEMALIGN
12468d75effSDimitry Andric INTERCEPTOR(void*, memalign, uptr alignment, uptr size) {
12568d75effSDimitry Andric   ENSURE_LSAN_INITED;
12668d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;
12768d75effSDimitry Andric   return lsan_memalign(alignment, size, stack);
12868d75effSDimitry Andric }
12968d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_MEMALIGN INTERCEPT_FUNCTION(memalign)
130e8d8bef9SDimitry Andric #else
131e8d8bef9SDimitry Andric #define LSAN_MAYBE_INTERCEPT_MEMALIGN
132e8d8bef9SDimitry Andric #endif  // SANITIZER_INTERCEPT_MEMALIGN
13368d75effSDimitry Andric 
134e8d8bef9SDimitry Andric #if SANITIZER_INTERCEPT___LIBC_MEMALIGN
13568d75effSDimitry Andric INTERCEPTOR(void *, __libc_memalign, uptr alignment, uptr size) {
13668d75effSDimitry Andric   ENSURE_LSAN_INITED;
13768d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;
13868d75effSDimitry Andric   void *res = lsan_memalign(alignment, size, stack);
13968d75effSDimitry Andric   DTLS_on_libc_memalign(res, size);
14068d75effSDimitry Andric   return res;
14168d75effSDimitry Andric }
14268d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN INTERCEPT_FUNCTION(__libc_memalign)
14368d75effSDimitry Andric #else
14468d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN
145e8d8bef9SDimitry Andric #endif  // SANITIZER_INTERCEPT___LIBC_MEMALIGN
14668d75effSDimitry Andric 
14768d75effSDimitry Andric #if SANITIZER_INTERCEPT_ALIGNED_ALLOC
14868d75effSDimitry Andric INTERCEPTOR(void*, aligned_alloc, uptr alignment, uptr size) {
14968d75effSDimitry Andric   ENSURE_LSAN_INITED;
15068d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;
15168d75effSDimitry Andric   return lsan_aligned_alloc(alignment, size, stack);
15268d75effSDimitry Andric }
15368d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC INTERCEPT_FUNCTION(aligned_alloc)
15468d75effSDimitry Andric #else
15568d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC
15668d75effSDimitry Andric #endif
15768d75effSDimitry Andric 
15868d75effSDimitry Andric #if SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE
15968d75effSDimitry Andric INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
16068d75effSDimitry Andric   ENSURE_LSAN_INITED;
16168d75effSDimitry Andric   return GetMallocUsableSize(ptr);
16268d75effSDimitry Andric }
16368d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE \
16468d75effSDimitry Andric         INTERCEPT_FUNCTION(malloc_usable_size)
16568d75effSDimitry Andric #else
16668d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE
16768d75effSDimitry Andric #endif
16868d75effSDimitry Andric 
16968d75effSDimitry Andric #if SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO
17068d75effSDimitry Andric struct fake_mallinfo {
17168d75effSDimitry Andric   int x[10];
17268d75effSDimitry Andric };
17368d75effSDimitry Andric 
17468d75effSDimitry Andric INTERCEPTOR(struct fake_mallinfo, mallinfo, void) {
17568d75effSDimitry Andric   struct fake_mallinfo res;
17668d75effSDimitry Andric   internal_memset(&res, 0, sizeof(res));
17768d75effSDimitry Andric   return res;
17868d75effSDimitry Andric }
17968d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_MALLINFO INTERCEPT_FUNCTION(mallinfo)
18068d75effSDimitry Andric 
18168d75effSDimitry Andric INTERCEPTOR(int, mallopt, int cmd, int value) {
18268d75effSDimitry Andric   return 0;
18368d75effSDimitry Andric }
18468d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_MALLOPT INTERCEPT_FUNCTION(mallopt)
18568d75effSDimitry Andric #else
18668d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_MALLINFO
18768d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_MALLOPT
18868d75effSDimitry Andric #endif // SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO
18968d75effSDimitry Andric 
19068d75effSDimitry Andric #if SANITIZER_INTERCEPT_PVALLOC
19168d75effSDimitry Andric INTERCEPTOR(void*, pvalloc, uptr size) {
19268d75effSDimitry Andric   ENSURE_LSAN_INITED;
19368d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;
19468d75effSDimitry Andric   return lsan_pvalloc(size, stack);
19568d75effSDimitry Andric }
19668d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_PVALLOC INTERCEPT_FUNCTION(pvalloc)
19768d75effSDimitry Andric #else
19868d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_PVALLOC
19968d75effSDimitry Andric #endif // SANITIZER_INTERCEPT_PVALLOC
20068d75effSDimitry Andric 
20168d75effSDimitry Andric #if SANITIZER_INTERCEPT_CFREE
20206c3fb27SDimitry Andric INTERCEPTOR(void, cfree, void *p) ALIAS(WRAP(free));
20368d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_CFREE INTERCEPT_FUNCTION(cfree)
20468d75effSDimitry Andric #else
20568d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_CFREE
20668d75effSDimitry Andric #endif // SANITIZER_INTERCEPT_CFREE
20768d75effSDimitry Andric 
20868d75effSDimitry Andric #if SANITIZER_INTERCEPT_MCHECK_MPROBE
20968d75effSDimitry Andric INTERCEPTOR(int, mcheck, void (*abortfunc)(int mstatus)) {
21068d75effSDimitry Andric   return 0;
21168d75effSDimitry Andric }
21268d75effSDimitry Andric 
21368d75effSDimitry Andric INTERCEPTOR(int, mcheck_pedantic, void (*abortfunc)(int mstatus)) {
21468d75effSDimitry Andric   return 0;
21568d75effSDimitry Andric }
21668d75effSDimitry Andric 
21768d75effSDimitry Andric INTERCEPTOR(int, mprobe, void *ptr) {
21868d75effSDimitry Andric   return 0;
21968d75effSDimitry Andric }
22068d75effSDimitry Andric #endif // SANITIZER_INTERCEPT_MCHECK_MPROBE
22168d75effSDimitry Andric 
22268d75effSDimitry Andric 
22368d75effSDimitry Andric // TODO(alekseys): throw std::bad_alloc instead of dying on OOM.
22468d75effSDimitry Andric #define OPERATOR_NEW_BODY(nothrow)\
22568d75effSDimitry Andric   ENSURE_LSAN_INITED;\
22668d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;\
22768d75effSDimitry Andric   void *res = lsan_malloc(size, stack);\
22868d75effSDimitry Andric   if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\
22968d75effSDimitry Andric   return res;
23068d75effSDimitry Andric #define OPERATOR_NEW_BODY_ALIGN(nothrow)\
23168d75effSDimitry Andric   ENSURE_LSAN_INITED;\
23268d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;\
23368d75effSDimitry Andric   void *res = lsan_memalign((uptr)align, size, stack);\
23468d75effSDimitry Andric   if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\
23568d75effSDimitry Andric   return res;
23668d75effSDimitry Andric 
23768d75effSDimitry Andric #define OPERATOR_DELETE_BODY\
23868d75effSDimitry Andric   ENSURE_LSAN_INITED;\
23968d75effSDimitry Andric   lsan_free(ptr);
24068d75effSDimitry Andric 
24168d75effSDimitry Andric // On OS X it's not enough to just provide our own 'operator new' and
24268d75effSDimitry Andric // 'operator delete' implementations, because they're going to be in the runtime
24368d75effSDimitry Andric // dylib, and the main executable will depend on both the runtime dylib and
24468d75effSDimitry Andric // libstdc++, each of has its implementation of new and delete.
24568d75effSDimitry Andric // To make sure that C++ allocation/deallocation operators are overridden on
24668d75effSDimitry Andric // OS X we need to intercept them using their mangled names.
24781ad6265SDimitry Andric #if !SANITIZER_APPLE
24868d75effSDimitry Andric 
24968d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
25068d75effSDimitry Andric void *operator new(size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); }
25168d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
25268d75effSDimitry Andric void *operator new[](size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); }
25368d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
25468d75effSDimitry Andric void *operator new(size_t size, std::nothrow_t const&)
25568d75effSDimitry Andric { OPERATOR_NEW_BODY(true /*nothrow*/); }
25668d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
25768d75effSDimitry Andric void *operator new[](size_t size, std::nothrow_t const&)
25868d75effSDimitry Andric { OPERATOR_NEW_BODY(true /*nothrow*/); }
25968d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
26068d75effSDimitry Andric void *operator new(size_t size, std::align_val_t align)
26168d75effSDimitry Andric { OPERATOR_NEW_BODY_ALIGN(false /*nothrow*/); }
26268d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
26368d75effSDimitry Andric void *operator new[](size_t size, std::align_val_t align)
26468d75effSDimitry Andric { OPERATOR_NEW_BODY_ALIGN(false /*nothrow*/); }
26568d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
26668d75effSDimitry Andric void *operator new(size_t size, std::align_val_t align, std::nothrow_t const&)
26768d75effSDimitry Andric { OPERATOR_NEW_BODY_ALIGN(true /*nothrow*/); }
26868d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
26968d75effSDimitry Andric void *operator new[](size_t size, std::align_val_t align, std::nothrow_t const&)
27068d75effSDimitry Andric { OPERATOR_NEW_BODY_ALIGN(true /*nothrow*/); }
27168d75effSDimitry Andric 
27268d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
27368d75effSDimitry Andric void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
27468d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
27568d75effSDimitry Andric void operator delete[](void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
27668d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
27768d75effSDimitry Andric void operator delete(void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY; }
27868d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
27968d75effSDimitry Andric void operator delete[](void *ptr, std::nothrow_t const &)
28068d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
28168d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
28268d75effSDimitry Andric void operator delete(void *ptr, size_t size) NOEXCEPT
28368d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
28468d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
28568d75effSDimitry Andric void operator delete[](void *ptr, size_t size) NOEXCEPT
28668d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
28768d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
28868d75effSDimitry Andric void operator delete(void *ptr, std::align_val_t) NOEXCEPT
28968d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
29068d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
29168d75effSDimitry Andric void operator delete[](void *ptr, std::align_val_t) NOEXCEPT
29268d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
29368d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
29468d75effSDimitry Andric void operator delete(void *ptr, std::align_val_t, std::nothrow_t const&)
29568d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
29668d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
29768d75effSDimitry Andric void operator delete[](void *ptr, std::align_val_t, std::nothrow_t const&)
29868d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
29968d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
30068d75effSDimitry Andric void operator delete(void *ptr, size_t size, std::align_val_t) NOEXCEPT
30168d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
30268d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
30368d75effSDimitry Andric void operator delete[](void *ptr, size_t size, std::align_val_t) NOEXCEPT
30468d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
30568d75effSDimitry Andric 
30681ad6265SDimitry Andric #else  // SANITIZER_APPLE
30768d75effSDimitry Andric 
30868d75effSDimitry Andric INTERCEPTOR(void *, _Znwm, size_t size)
30968d75effSDimitry Andric { OPERATOR_NEW_BODY(false /*nothrow*/); }
31068d75effSDimitry Andric INTERCEPTOR(void *, _Znam, size_t size)
31168d75effSDimitry Andric { OPERATOR_NEW_BODY(false /*nothrow*/); }
31268d75effSDimitry Andric INTERCEPTOR(void *, _ZnwmRKSt9nothrow_t, size_t size, std::nothrow_t const&)
31368d75effSDimitry Andric { OPERATOR_NEW_BODY(true /*nothrow*/); }
31468d75effSDimitry Andric INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&)
31568d75effSDimitry Andric { OPERATOR_NEW_BODY(true /*nothrow*/); }
31668d75effSDimitry Andric 
31768d75effSDimitry Andric INTERCEPTOR(void, _ZdlPv, void *ptr)
31868d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
31968d75effSDimitry Andric INTERCEPTOR(void, _ZdaPv, void *ptr)
32068d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
32168d75effSDimitry Andric INTERCEPTOR(void, _ZdlPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&)
32268d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
32368d75effSDimitry Andric INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&)
32468d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
32568d75effSDimitry Andric 
32681ad6265SDimitry Andric #endif  // !SANITIZER_APPLE
32768d75effSDimitry Andric 
32868d75effSDimitry Andric 
32968d75effSDimitry Andric ///// Thread initialization and finalization. /////
33068d75effSDimitry Andric 
3315ffd83dbSDimitry Andric #if !SANITIZER_NETBSD && !SANITIZER_FREEBSD && !SANITIZER_FUCHSIA
33268d75effSDimitry Andric static unsigned g_thread_finalize_key;
33368d75effSDimitry Andric 
33468d75effSDimitry Andric static void thread_finalize(void *v) {
33568d75effSDimitry Andric   uptr iter = (uptr)v;
33668d75effSDimitry Andric   if (iter > 1) {
33768d75effSDimitry Andric     if (pthread_setspecific(g_thread_finalize_key, (void*)(iter - 1))) {
33868d75effSDimitry Andric       Report("LeakSanitizer: failed to set thread key.\n");
33968d75effSDimitry Andric       Die();
34068d75effSDimitry Andric     }
34168d75effSDimitry Andric     return;
34268d75effSDimitry Andric   }
34368d75effSDimitry Andric   ThreadFinish();
34468d75effSDimitry Andric }
34568d75effSDimitry Andric #endif
34668d75effSDimitry Andric 
34768d75effSDimitry Andric #if SANITIZER_NETBSD
34868d75effSDimitry Andric INTERCEPTOR(void, _lwp_exit) {
34968d75effSDimitry Andric   ENSURE_LSAN_INITED;
35068d75effSDimitry Andric   ThreadFinish();
35168d75effSDimitry Andric   REAL(_lwp_exit)();
35268d75effSDimitry Andric }
35368d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT__LWP_EXIT INTERCEPT_FUNCTION(_lwp_exit)
35468d75effSDimitry Andric #else
35568d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT__LWP_EXIT
35668d75effSDimitry Andric #endif
35768d75effSDimitry Andric 
35868d75effSDimitry Andric #if SANITIZER_INTERCEPT_THR_EXIT
35968d75effSDimitry Andric INTERCEPTOR(void, thr_exit, tid_t *state) {
36068d75effSDimitry Andric   ENSURE_LSAN_INITED;
36168d75effSDimitry Andric   ThreadFinish();
36268d75effSDimitry Andric   REAL(thr_exit)(state);
36368d75effSDimitry Andric }
36468d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_THR_EXIT INTERCEPT_FUNCTION(thr_exit)
36568d75effSDimitry Andric #else
36668d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_THR_EXIT
36768d75effSDimitry Andric #endif
36868d75effSDimitry Andric 
36968d75effSDimitry Andric #if SANITIZER_INTERCEPT___CXA_ATEXIT
37068d75effSDimitry Andric INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
37168d75effSDimitry Andric             void *dso_handle) {
37268d75effSDimitry Andric   __lsan::ScopedInterceptorDisabler disabler;
37368d75effSDimitry Andric   return REAL(__cxa_atexit)(func, arg, dso_handle);
37468d75effSDimitry Andric }
37568d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT___CXA_ATEXIT INTERCEPT_FUNCTION(__cxa_atexit)
37668d75effSDimitry Andric #else
37768d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT___CXA_ATEXIT
37868d75effSDimitry Andric #endif
37968d75effSDimitry Andric 
38068d75effSDimitry Andric #if SANITIZER_INTERCEPT_ATEXIT
38168d75effSDimitry Andric INTERCEPTOR(int, atexit, void (*f)()) {
38268d75effSDimitry Andric   __lsan::ScopedInterceptorDisabler disabler;
38368d75effSDimitry Andric   return REAL(__cxa_atexit)((void (*)(void *a))f, 0, 0);
38468d75effSDimitry Andric }
38568d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_ATEXIT INTERCEPT_FUNCTION(atexit)
38668d75effSDimitry Andric #else
38768d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_ATEXIT
38868d75effSDimitry Andric #endif
38968d75effSDimitry Andric 
39068d75effSDimitry Andric #if SANITIZER_INTERCEPT_PTHREAD_ATFORK
39168d75effSDimitry Andric extern "C" {
39268d75effSDimitry Andric extern int _pthread_atfork(void (*prepare)(), void (*parent)(),
39368d75effSDimitry Andric                            void (*child)());
3940fca6ea1SDimitry Andric }
39568d75effSDimitry Andric 
39668d75effSDimitry Andric INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(),
39768d75effSDimitry Andric             void (*child)()) {
39868d75effSDimitry Andric   __lsan::ScopedInterceptorDisabler disabler;
39968d75effSDimitry Andric   // REAL(pthread_atfork) cannot be called due to symbol indirections at least
40068d75effSDimitry Andric   // on NetBSD
40168d75effSDimitry Andric   return _pthread_atfork(prepare, parent, child);
40268d75effSDimitry Andric }
40368d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK INTERCEPT_FUNCTION(pthread_atfork)
40468d75effSDimitry Andric #else
40568d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK
40668d75effSDimitry Andric #endif
40768d75effSDimitry Andric 
40868d75effSDimitry Andric #if SANITIZER_INTERCEPT_STRERROR
40968d75effSDimitry Andric INTERCEPTOR(char *, strerror, int errnum) {
41068d75effSDimitry Andric   __lsan::ScopedInterceptorDisabler disabler;
41168d75effSDimitry Andric   return REAL(strerror)(errnum);
41268d75effSDimitry Andric }
41368d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_STRERROR INTERCEPT_FUNCTION(strerror)
41468d75effSDimitry Andric #else
41568d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_STRERROR
41668d75effSDimitry Andric #endif
41768d75effSDimitry Andric 
4185ffd83dbSDimitry Andric #if SANITIZER_POSIX
4195ffd83dbSDimitry Andric 
42006c3fb27SDimitry Andric template <bool Detached>
42106c3fb27SDimitry Andric static void *ThreadStartFunc(void *arg) {
42206c3fb27SDimitry Andric   u32 parent_tid = (uptr)arg;
42306c3fb27SDimitry Andric   uptr tid = ThreadCreate(parent_tid, Detached);
42468d75effSDimitry Andric   // Wait until the last iteration to maximize the chance that we are the last
42568d75effSDimitry Andric   // destructor to run.
42668d75effSDimitry Andric #if !SANITIZER_NETBSD && !SANITIZER_FREEBSD
42768d75effSDimitry Andric   if (pthread_setspecific(g_thread_finalize_key,
42868d75effSDimitry Andric                           (void*)GetPthreadDestructorIterations())) {
42968d75effSDimitry Andric     Report("LeakSanitizer: failed to set thread key.\n");
43068d75effSDimitry Andric     Die();
43168d75effSDimitry Andric   }
43268d75effSDimitry Andric #  endif
43368d75effSDimitry Andric   ThreadStart(tid, GetTid());
43406c3fb27SDimitry Andric   auto self = GetThreadSelf();
43506c3fb27SDimitry Andric   auto args = GetThreadArgRetval().GetArgs(self);
43606c3fb27SDimitry Andric   void *retval = (*args.routine)(args.arg_retval);
43706c3fb27SDimitry Andric   GetThreadArgRetval().Finish(self, retval);
43806c3fb27SDimitry Andric   return retval;
43968d75effSDimitry Andric }
44068d75effSDimitry Andric 
44168d75effSDimitry Andric INTERCEPTOR(int, pthread_create, void *th, void *attr,
44268d75effSDimitry Andric             void *(*callback)(void *), void *param) {
44368d75effSDimitry Andric   ENSURE_LSAN_INITED;
44468d75effSDimitry Andric   EnsureMainThreadIDIsCorrect();
44506c3fb27SDimitry Andric 
44606c3fb27SDimitry Andric   bool detached = [attr]() {
44706c3fb27SDimitry Andric     int d = 0;
44806c3fb27SDimitry Andric     return attr && !pthread_attr_getdetachstate(attr, &d) && IsStateDetached(d);
44906c3fb27SDimitry Andric   }();
45006c3fb27SDimitry Andric 
45168d75effSDimitry Andric   __sanitizer_pthread_attr_t myattr;
45268d75effSDimitry Andric   if (!attr) {
45368d75effSDimitry Andric     pthread_attr_init(&myattr);
45468d75effSDimitry Andric     attr = &myattr;
45568d75effSDimitry Andric   }
45668d75effSDimitry Andric   AdjustStackSize(attr);
45706c3fb27SDimitry Andric   uptr this_tid = GetCurrentThreadId();
45806c3fb27SDimitry Andric   int result;
45968d75effSDimitry Andric   {
46068d75effSDimitry Andric     // Ignore all allocations made by pthread_create: thread stack/TLS may be
46168d75effSDimitry Andric     // stored by pthread for future reuse even after thread destruction, and
46268d75effSDimitry Andric     // the linked list it's stored in doesn't even hold valid pointers to the
46368d75effSDimitry Andric     // objects, the latter are calculated by obscure pointer arithmetic.
46468d75effSDimitry Andric     ScopedInterceptorDisabler disabler;
46506c3fb27SDimitry Andric     GetThreadArgRetval().Create(detached, {callback, param}, [&]() -> uptr {
46606c3fb27SDimitry Andric       result = REAL(pthread_create)(
46706c3fb27SDimitry Andric           th, attr, detached ? ThreadStartFunc<true> : ThreadStartFunc<false>,
46806c3fb27SDimitry Andric           (void *)this_tid);
46906c3fb27SDimitry Andric       return result ? 0 : *(uptr *)(th);
47006c3fb27SDimitry Andric     });
47168d75effSDimitry Andric   }
47268d75effSDimitry Andric   if (attr == &myattr)
47368d75effSDimitry Andric     pthread_attr_destroy(&myattr);
47406c3fb27SDimitry Andric   return result;
47568d75effSDimitry Andric }
47668d75effSDimitry Andric 
47706c3fb27SDimitry Andric INTERCEPTOR(int, pthread_join, void *thread, void **retval) {
47806c3fb27SDimitry Andric   int result;
47906c3fb27SDimitry Andric   GetThreadArgRetval().Join((uptr)thread, [&]() {
48006c3fb27SDimitry Andric     result = REAL(pthread_join)(thread, retval);
48106c3fb27SDimitry Andric     return !result;
48206c3fb27SDimitry Andric   });
48306c3fb27SDimitry Andric   return result;
4840eae32dcSDimitry Andric }
4850eae32dcSDimitry Andric 
48606c3fb27SDimitry Andric INTERCEPTOR(int, pthread_detach, void *thread) {
48706c3fb27SDimitry Andric   int result;
48806c3fb27SDimitry Andric   GetThreadArgRetval().Detach((uptr)thread, [&]() {
48906c3fb27SDimitry Andric     result = REAL(pthread_detach)(thread);
49006c3fb27SDimitry Andric     return !result;
49106c3fb27SDimitry Andric   });
49206c3fb27SDimitry Andric   return result;
49306c3fb27SDimitry Andric }
49406c3fb27SDimitry Andric 
4955f757f3fSDimitry Andric INTERCEPTOR(void, pthread_exit, void *retval) {
49606c3fb27SDimitry Andric   GetThreadArgRetval().Finish(GetThreadSelf(), retval);
4975f757f3fSDimitry Andric   REAL(pthread_exit)(retval);
49806c3fb27SDimitry Andric }
49906c3fb27SDimitry Andric 
50006c3fb27SDimitry Andric #  if SANITIZER_INTERCEPT_TRYJOIN
50106c3fb27SDimitry Andric INTERCEPTOR(int, pthread_tryjoin_np, void *thread, void **ret) {
50206c3fb27SDimitry Andric   int result;
50306c3fb27SDimitry Andric   GetThreadArgRetval().Join((uptr)thread, [&]() {
50406c3fb27SDimitry Andric     result = REAL(pthread_tryjoin_np)(thread, ret);
50506c3fb27SDimitry Andric     return !result;
50606c3fb27SDimitry Andric   });
50706c3fb27SDimitry Andric   return result;
50806c3fb27SDimitry Andric }
50906c3fb27SDimitry Andric #    define LSAN_MAYBE_INTERCEPT_TRYJOIN INTERCEPT_FUNCTION(pthread_tryjoin_np)
51006c3fb27SDimitry Andric #  else
51106c3fb27SDimitry Andric #    define LSAN_MAYBE_INTERCEPT_TRYJOIN
51206c3fb27SDimitry Andric #  endif  // SANITIZER_INTERCEPT_TRYJOIN
51306c3fb27SDimitry Andric 
51406c3fb27SDimitry Andric #  if SANITIZER_INTERCEPT_TIMEDJOIN
51506c3fb27SDimitry Andric INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **ret,
51606c3fb27SDimitry Andric             const struct timespec *abstime) {
51706c3fb27SDimitry Andric   int result;
51806c3fb27SDimitry Andric   GetThreadArgRetval().Join((uptr)thread, [&]() {
51906c3fb27SDimitry Andric     result = REAL(pthread_timedjoin_np)(thread, ret, abstime);
52006c3fb27SDimitry Andric     return !result;
52106c3fb27SDimitry Andric   });
52206c3fb27SDimitry Andric   return result;
52306c3fb27SDimitry Andric }
52406c3fb27SDimitry Andric #    define LSAN_MAYBE_INTERCEPT_TIMEDJOIN \
52506c3fb27SDimitry Andric       INTERCEPT_FUNCTION(pthread_timedjoin_np)
52606c3fb27SDimitry Andric #  else
52706c3fb27SDimitry Andric #    define LSAN_MAYBE_INTERCEPT_TIMEDJOIN
52806c3fb27SDimitry Andric #  endif  // SANITIZER_INTERCEPT_TIMEDJOIN
52906c3fb27SDimitry Andric 
5300fca6ea1SDimitry Andric DEFINE_INTERNAL_PTHREAD_FUNCTIONS
5310eae32dcSDimitry Andric 
53268d75effSDimitry Andric INTERCEPTOR(void, _exit, int status) {
53368d75effSDimitry Andric   if (status == 0 && HasReportedLeaks()) status = common_flags()->exitcode;
53468d75effSDimitry Andric   REAL(_exit)(status);
53568d75effSDimitry Andric }
53668d75effSDimitry Andric 
53768d75effSDimitry Andric #define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name)
53806c3fb27SDimitry Andric #define SIGNAL_INTERCEPTOR_ENTER() ENSURE_LSAN_INITED
53968d75effSDimitry Andric #include "sanitizer_common/sanitizer_signal_interceptors.inc"
54068d75effSDimitry Andric 
5415ffd83dbSDimitry Andric #endif  // SANITIZER_POSIX
5425ffd83dbSDimitry Andric 
54368d75effSDimitry Andric namespace __lsan {
54468d75effSDimitry Andric 
54568d75effSDimitry Andric void InitializeInterceptors() {
5465ffd83dbSDimitry Andric   // Fuchsia doesn't use interceptors that require any setup.
5475ffd83dbSDimitry Andric #if !SANITIZER_FUCHSIA
5480fca6ea1SDimitry Andric   __interception::DoesNotSupportStaticLinking();
54968d75effSDimitry Andric   InitializeSignalInterceptors();
55068d75effSDimitry Andric 
55168d75effSDimitry Andric   INTERCEPT_FUNCTION(malloc);
55268d75effSDimitry Andric   INTERCEPT_FUNCTION(free);
55368d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_CFREE;
55468d75effSDimitry Andric   INTERCEPT_FUNCTION(calloc);
55568d75effSDimitry Andric   INTERCEPT_FUNCTION(realloc);
55668d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_MEMALIGN;
55768d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN;
55868d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC;
55968d75effSDimitry Andric   INTERCEPT_FUNCTION(posix_memalign);
56068d75effSDimitry Andric   INTERCEPT_FUNCTION(valloc);
56168d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_PVALLOC;
56268d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE;
56368d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_MALLINFO;
56468d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_MALLOPT;
56568d75effSDimitry Andric   INTERCEPT_FUNCTION(pthread_create);
5660eae32dcSDimitry Andric   INTERCEPT_FUNCTION(pthread_join);
56706c3fb27SDimitry Andric   INTERCEPT_FUNCTION(pthread_detach);
56806c3fb27SDimitry Andric   INTERCEPT_FUNCTION(pthread_exit);
56906c3fb27SDimitry Andric   LSAN_MAYBE_INTERCEPT_TIMEDJOIN;
57006c3fb27SDimitry Andric   LSAN_MAYBE_INTERCEPT_TRYJOIN;
57168d75effSDimitry Andric   INTERCEPT_FUNCTION(_exit);
57268d75effSDimitry Andric 
57368d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT__LWP_EXIT;
57468d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_THR_EXIT;
57568d75effSDimitry Andric 
57668d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT___CXA_ATEXIT;
57768d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_ATEXIT;
57868d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK;
57968d75effSDimitry Andric 
58068d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_STRERROR;
58168d75effSDimitry Andric 
58268d75effSDimitry Andric #if !SANITIZER_NETBSD && !SANITIZER_FREEBSD
58368d75effSDimitry Andric   if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) {
58468d75effSDimitry Andric     Report("LeakSanitizer: failed to create thread key.\n");
58568d75effSDimitry Andric     Die();
58668d75effSDimitry Andric   }
58768d75effSDimitry Andric #endif
5885ffd83dbSDimitry Andric 
5895ffd83dbSDimitry Andric #endif  // !SANITIZER_FUCHSIA
59068d75effSDimitry Andric }
59168d75effSDimitry Andric 
59268d75effSDimitry Andric } // namespace __lsan
593