xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/lsan/lsan_interceptors.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
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) {
80349cc55cSDimitry Andric   if (DlsymAlloc::PointerIsMine(p))
81349cc55cSDimitry Andric     return DlsymAlloc::Free(p);
8268d75effSDimitry Andric   ENSURE_LSAN_INITED;
8368d75effSDimitry Andric   lsan_free(p);
8468d75effSDimitry Andric }
8568d75effSDimitry Andric 
8668d75effSDimitry Andric INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
87349cc55cSDimitry Andric   if (DlsymAlloc::Use())
88349cc55cSDimitry Andric     return DlsymAlloc::Callocate(nmemb, size);
8968d75effSDimitry Andric   ENSURE_LSAN_INITED;
9068d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;
9168d75effSDimitry Andric   return lsan_calloc(nmemb, size, stack);
9268d75effSDimitry Andric }
9368d75effSDimitry Andric 
94349cc55cSDimitry Andric INTERCEPTOR(void *, realloc, void *ptr, uptr size) {
95349cc55cSDimitry Andric   if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr))
96349cc55cSDimitry Andric     return DlsymAlloc::Realloc(ptr, size);
9768d75effSDimitry Andric   ENSURE_LSAN_INITED;
9868d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;
99349cc55cSDimitry Andric   return lsan_realloc(ptr, size, stack);
10068d75effSDimitry Andric }
10168d75effSDimitry Andric 
10268d75effSDimitry Andric INTERCEPTOR(void*, reallocarray, void *q, uptr nmemb, uptr size) {
10368d75effSDimitry Andric   ENSURE_LSAN_INITED;
10468d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;
10568d75effSDimitry Andric   return lsan_reallocarray(q, nmemb, size, stack);
10668d75effSDimitry Andric }
10768d75effSDimitry Andric 
10868d75effSDimitry Andric INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
10968d75effSDimitry Andric   ENSURE_LSAN_INITED;
11068d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;
11168d75effSDimitry Andric   return lsan_posix_memalign(memptr, alignment, size, stack);
11268d75effSDimitry Andric }
11368d75effSDimitry Andric 
11468d75effSDimitry Andric INTERCEPTOR(void*, valloc, uptr size) {
11568d75effSDimitry Andric   ENSURE_LSAN_INITED;
11668d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;
11768d75effSDimitry Andric   return lsan_valloc(size, stack);
11868d75effSDimitry Andric }
11981ad6265SDimitry Andric #endif  // !SANITIZER_APPLE
12068d75effSDimitry Andric 
12168d75effSDimitry Andric #if SANITIZER_INTERCEPT_MEMALIGN
12268d75effSDimitry Andric INTERCEPTOR(void*, memalign, uptr alignment, uptr size) {
12368d75effSDimitry Andric   ENSURE_LSAN_INITED;
12468d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;
12568d75effSDimitry Andric   return lsan_memalign(alignment, size, stack);
12668d75effSDimitry Andric }
12768d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_MEMALIGN INTERCEPT_FUNCTION(memalign)
128e8d8bef9SDimitry Andric #else
129e8d8bef9SDimitry Andric #define LSAN_MAYBE_INTERCEPT_MEMALIGN
130e8d8bef9SDimitry Andric #endif  // SANITIZER_INTERCEPT_MEMALIGN
13168d75effSDimitry Andric 
132e8d8bef9SDimitry Andric #if SANITIZER_INTERCEPT___LIBC_MEMALIGN
13368d75effSDimitry Andric INTERCEPTOR(void *, __libc_memalign, uptr alignment, uptr size) {
13468d75effSDimitry Andric   ENSURE_LSAN_INITED;
13568d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;
13668d75effSDimitry Andric   void *res = lsan_memalign(alignment, size, stack);
13768d75effSDimitry Andric   DTLS_on_libc_memalign(res, size);
13868d75effSDimitry Andric   return res;
13968d75effSDimitry Andric }
14068d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN INTERCEPT_FUNCTION(__libc_memalign)
14168d75effSDimitry Andric #else
14268d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN
143e8d8bef9SDimitry Andric #endif  // SANITIZER_INTERCEPT___LIBC_MEMALIGN
14468d75effSDimitry Andric 
14568d75effSDimitry Andric #if SANITIZER_INTERCEPT_ALIGNED_ALLOC
14668d75effSDimitry Andric INTERCEPTOR(void*, aligned_alloc, uptr alignment, uptr size) {
14768d75effSDimitry Andric   ENSURE_LSAN_INITED;
14868d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;
14968d75effSDimitry Andric   return lsan_aligned_alloc(alignment, size, stack);
15068d75effSDimitry Andric }
15168d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC INTERCEPT_FUNCTION(aligned_alloc)
15268d75effSDimitry Andric #else
15368d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC
15468d75effSDimitry Andric #endif
15568d75effSDimitry Andric 
15668d75effSDimitry Andric #if SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE
15768d75effSDimitry Andric INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
15868d75effSDimitry Andric   ENSURE_LSAN_INITED;
15968d75effSDimitry Andric   return GetMallocUsableSize(ptr);
16068d75effSDimitry Andric }
16168d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE \
16268d75effSDimitry Andric         INTERCEPT_FUNCTION(malloc_usable_size)
16368d75effSDimitry Andric #else
16468d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE
16568d75effSDimitry Andric #endif
16668d75effSDimitry Andric 
16768d75effSDimitry Andric #if SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO
16868d75effSDimitry Andric struct fake_mallinfo {
16968d75effSDimitry Andric   int x[10];
17068d75effSDimitry Andric };
17168d75effSDimitry Andric 
17268d75effSDimitry Andric INTERCEPTOR(struct fake_mallinfo, mallinfo, void) {
17368d75effSDimitry Andric   struct fake_mallinfo res;
17468d75effSDimitry Andric   internal_memset(&res, 0, sizeof(res));
17568d75effSDimitry Andric   return res;
17668d75effSDimitry Andric }
17768d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_MALLINFO INTERCEPT_FUNCTION(mallinfo)
17868d75effSDimitry Andric 
17968d75effSDimitry Andric INTERCEPTOR(int, mallopt, int cmd, int value) {
18068d75effSDimitry Andric   return 0;
18168d75effSDimitry Andric }
18268d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_MALLOPT INTERCEPT_FUNCTION(mallopt)
18368d75effSDimitry Andric #else
18468d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_MALLINFO
18568d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_MALLOPT
18668d75effSDimitry Andric #endif // SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO
18768d75effSDimitry Andric 
18868d75effSDimitry Andric #if SANITIZER_INTERCEPT_PVALLOC
18968d75effSDimitry Andric INTERCEPTOR(void*, pvalloc, uptr size) {
19068d75effSDimitry Andric   ENSURE_LSAN_INITED;
19168d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;
19268d75effSDimitry Andric   return lsan_pvalloc(size, stack);
19368d75effSDimitry Andric }
19468d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_PVALLOC INTERCEPT_FUNCTION(pvalloc)
19568d75effSDimitry Andric #else
19668d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_PVALLOC
19768d75effSDimitry Andric #endif // SANITIZER_INTERCEPT_PVALLOC
19868d75effSDimitry Andric 
19968d75effSDimitry Andric #if SANITIZER_INTERCEPT_CFREE
200*06c3fb27SDimitry Andric INTERCEPTOR(void, cfree, void *p) ALIAS(WRAP(free));
20168d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_CFREE INTERCEPT_FUNCTION(cfree)
20268d75effSDimitry Andric #else
20368d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_CFREE
20468d75effSDimitry Andric #endif // SANITIZER_INTERCEPT_CFREE
20568d75effSDimitry Andric 
20668d75effSDimitry Andric #if SANITIZER_INTERCEPT_MCHECK_MPROBE
20768d75effSDimitry Andric INTERCEPTOR(int, mcheck, void (*abortfunc)(int mstatus)) {
20868d75effSDimitry Andric   return 0;
20968d75effSDimitry Andric }
21068d75effSDimitry Andric 
21168d75effSDimitry Andric INTERCEPTOR(int, mcheck_pedantic, void (*abortfunc)(int mstatus)) {
21268d75effSDimitry Andric   return 0;
21368d75effSDimitry Andric }
21468d75effSDimitry Andric 
21568d75effSDimitry Andric INTERCEPTOR(int, mprobe, void *ptr) {
21668d75effSDimitry Andric   return 0;
21768d75effSDimitry Andric }
21868d75effSDimitry Andric #endif // SANITIZER_INTERCEPT_MCHECK_MPROBE
21968d75effSDimitry Andric 
22068d75effSDimitry Andric 
22168d75effSDimitry Andric // TODO(alekseys): throw std::bad_alloc instead of dying on OOM.
22268d75effSDimitry Andric #define OPERATOR_NEW_BODY(nothrow)\
22368d75effSDimitry Andric   ENSURE_LSAN_INITED;\
22468d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;\
22568d75effSDimitry Andric   void *res = lsan_malloc(size, stack);\
22668d75effSDimitry Andric   if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\
22768d75effSDimitry Andric   return res;
22868d75effSDimitry Andric #define OPERATOR_NEW_BODY_ALIGN(nothrow)\
22968d75effSDimitry Andric   ENSURE_LSAN_INITED;\
23068d75effSDimitry Andric   GET_STACK_TRACE_MALLOC;\
23168d75effSDimitry Andric   void *res = lsan_memalign((uptr)align, size, stack);\
23268d75effSDimitry Andric   if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\
23368d75effSDimitry Andric   return res;
23468d75effSDimitry Andric 
23568d75effSDimitry Andric #define OPERATOR_DELETE_BODY\
23668d75effSDimitry Andric   ENSURE_LSAN_INITED;\
23768d75effSDimitry Andric   lsan_free(ptr);
23868d75effSDimitry Andric 
23968d75effSDimitry Andric // On OS X it's not enough to just provide our own 'operator new' and
24068d75effSDimitry Andric // 'operator delete' implementations, because they're going to be in the runtime
24168d75effSDimitry Andric // dylib, and the main executable will depend on both the runtime dylib and
24268d75effSDimitry Andric // libstdc++, each of has its implementation of new and delete.
24368d75effSDimitry Andric // To make sure that C++ allocation/deallocation operators are overridden on
24468d75effSDimitry Andric // OS X we need to intercept them using their mangled names.
24581ad6265SDimitry Andric #if !SANITIZER_APPLE
24668d75effSDimitry Andric 
24768d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
24868d75effSDimitry Andric void *operator new(size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); }
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, std::nothrow_t const&)
25368d75effSDimitry Andric { OPERATOR_NEW_BODY(true /*nothrow*/); }
25468d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
25568d75effSDimitry Andric void *operator new[](size_t size, std::nothrow_t const&)
25668d75effSDimitry Andric { OPERATOR_NEW_BODY(true /*nothrow*/); }
25768d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
25868d75effSDimitry Andric void *operator new(size_t size, std::align_val_t align)
25968d75effSDimitry Andric { OPERATOR_NEW_BODY_ALIGN(false /*nothrow*/); }
26068d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
26168d75effSDimitry Andric void *operator new[](size_t size, std::align_val_t align)
26268d75effSDimitry Andric { OPERATOR_NEW_BODY_ALIGN(false /*nothrow*/); }
26368d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
26468d75effSDimitry Andric void *operator new(size_t size, std::align_val_t align, std::nothrow_t const&)
26568d75effSDimitry Andric { OPERATOR_NEW_BODY_ALIGN(true /*nothrow*/); }
26668d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
26768d75effSDimitry Andric void *operator new[](size_t size, std::align_val_t align, std::nothrow_t const&)
26868d75effSDimitry Andric { OPERATOR_NEW_BODY_ALIGN(true /*nothrow*/); }
26968d75effSDimitry Andric 
27068d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
27168d75effSDimitry Andric void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
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, std::nothrow_t const&) { OPERATOR_DELETE_BODY; }
27668d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
27768d75effSDimitry Andric void operator delete[](void *ptr, std::nothrow_t const &)
27868d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
27968d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
28068d75effSDimitry Andric void operator delete(void *ptr, size_t size) NOEXCEPT
28168d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
28268d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
28368d75effSDimitry Andric void operator delete[](void *ptr, size_t size) NOEXCEPT
28468d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
28568d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
28668d75effSDimitry Andric void operator delete(void *ptr, std::align_val_t) NOEXCEPT
28768d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
28868d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
28968d75effSDimitry Andric void operator delete[](void *ptr, std::align_val_t) NOEXCEPT
29068d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
29168d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
29268d75effSDimitry Andric void operator delete(void *ptr, std::align_val_t, std::nothrow_t const&)
29368d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
29468d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
29568d75effSDimitry Andric void operator delete[](void *ptr, std::align_val_t, std::nothrow_t const&)
29668d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
29768d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
29868d75effSDimitry Andric void operator delete(void *ptr, size_t size, std::align_val_t) NOEXCEPT
29968d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
30068d75effSDimitry Andric INTERCEPTOR_ATTRIBUTE
30168d75effSDimitry Andric void operator delete[](void *ptr, size_t size, std::align_val_t) NOEXCEPT
30268d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
30368d75effSDimitry Andric 
30481ad6265SDimitry Andric #else  // SANITIZER_APPLE
30568d75effSDimitry Andric 
30668d75effSDimitry Andric INTERCEPTOR(void *, _Znwm, size_t size)
30768d75effSDimitry Andric { OPERATOR_NEW_BODY(false /*nothrow*/); }
30868d75effSDimitry Andric INTERCEPTOR(void *, _Znam, size_t size)
30968d75effSDimitry Andric { OPERATOR_NEW_BODY(false /*nothrow*/); }
31068d75effSDimitry Andric INTERCEPTOR(void *, _ZnwmRKSt9nothrow_t, size_t size, std::nothrow_t const&)
31168d75effSDimitry Andric { OPERATOR_NEW_BODY(true /*nothrow*/); }
31268d75effSDimitry Andric INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&)
31368d75effSDimitry Andric { OPERATOR_NEW_BODY(true /*nothrow*/); }
31468d75effSDimitry Andric 
31568d75effSDimitry Andric INTERCEPTOR(void, _ZdlPv, void *ptr)
31668d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
31768d75effSDimitry Andric INTERCEPTOR(void, _ZdaPv, void *ptr)
31868d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
31968d75effSDimitry Andric INTERCEPTOR(void, _ZdlPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&)
32068d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
32168d75effSDimitry Andric INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&)
32268d75effSDimitry Andric { OPERATOR_DELETE_BODY; }
32368d75effSDimitry Andric 
32481ad6265SDimitry Andric #endif  // !SANITIZER_APPLE
32568d75effSDimitry Andric 
32668d75effSDimitry Andric 
32768d75effSDimitry Andric ///// Thread initialization and finalization. /////
32868d75effSDimitry Andric 
3295ffd83dbSDimitry Andric #if !SANITIZER_NETBSD && !SANITIZER_FREEBSD && !SANITIZER_FUCHSIA
33068d75effSDimitry Andric static unsigned g_thread_finalize_key;
33168d75effSDimitry Andric 
33268d75effSDimitry Andric static void thread_finalize(void *v) {
33368d75effSDimitry Andric   uptr iter = (uptr)v;
33468d75effSDimitry Andric   if (iter > 1) {
33568d75effSDimitry Andric     if (pthread_setspecific(g_thread_finalize_key, (void*)(iter - 1))) {
33668d75effSDimitry Andric       Report("LeakSanitizer: failed to set thread key.\n");
33768d75effSDimitry Andric       Die();
33868d75effSDimitry Andric     }
33968d75effSDimitry Andric     return;
34068d75effSDimitry Andric   }
34168d75effSDimitry Andric   ThreadFinish();
34268d75effSDimitry Andric }
34368d75effSDimitry Andric #endif
34468d75effSDimitry Andric 
34568d75effSDimitry Andric #if SANITIZER_NETBSD
34668d75effSDimitry Andric INTERCEPTOR(void, _lwp_exit) {
34768d75effSDimitry Andric   ENSURE_LSAN_INITED;
34868d75effSDimitry Andric   ThreadFinish();
34968d75effSDimitry Andric   REAL(_lwp_exit)();
35068d75effSDimitry Andric }
35168d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT__LWP_EXIT INTERCEPT_FUNCTION(_lwp_exit)
35268d75effSDimitry Andric #else
35368d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT__LWP_EXIT
35468d75effSDimitry Andric #endif
35568d75effSDimitry Andric 
35668d75effSDimitry Andric #if SANITIZER_INTERCEPT_THR_EXIT
35768d75effSDimitry Andric INTERCEPTOR(void, thr_exit, tid_t *state) {
35868d75effSDimitry Andric   ENSURE_LSAN_INITED;
35968d75effSDimitry Andric   ThreadFinish();
36068d75effSDimitry Andric   REAL(thr_exit)(state);
36168d75effSDimitry Andric }
36268d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_THR_EXIT INTERCEPT_FUNCTION(thr_exit)
36368d75effSDimitry Andric #else
36468d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_THR_EXIT
36568d75effSDimitry Andric #endif
36668d75effSDimitry Andric 
36768d75effSDimitry Andric #if SANITIZER_INTERCEPT___CXA_ATEXIT
36868d75effSDimitry Andric INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
36968d75effSDimitry Andric             void *dso_handle) {
37068d75effSDimitry Andric   __lsan::ScopedInterceptorDisabler disabler;
37168d75effSDimitry Andric   return REAL(__cxa_atexit)(func, arg, dso_handle);
37268d75effSDimitry Andric }
37368d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT___CXA_ATEXIT INTERCEPT_FUNCTION(__cxa_atexit)
37468d75effSDimitry Andric #else
37568d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT___CXA_ATEXIT
37668d75effSDimitry Andric #endif
37768d75effSDimitry Andric 
37868d75effSDimitry Andric #if SANITIZER_INTERCEPT_ATEXIT
37968d75effSDimitry Andric INTERCEPTOR(int, atexit, void (*f)()) {
38068d75effSDimitry Andric   __lsan::ScopedInterceptorDisabler disabler;
38168d75effSDimitry Andric   return REAL(__cxa_atexit)((void (*)(void *a))f, 0, 0);
38268d75effSDimitry Andric }
38368d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_ATEXIT INTERCEPT_FUNCTION(atexit)
38468d75effSDimitry Andric #else
38568d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_ATEXIT
38668d75effSDimitry Andric #endif
38768d75effSDimitry Andric 
38868d75effSDimitry Andric #if SANITIZER_INTERCEPT_PTHREAD_ATFORK
38968d75effSDimitry Andric extern "C" {
39068d75effSDimitry Andric extern int _pthread_atfork(void (*prepare)(), void (*parent)(),
39168d75effSDimitry Andric                            void (*child)());
39268d75effSDimitry Andric };
39368d75effSDimitry Andric 
39468d75effSDimitry Andric INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(),
39568d75effSDimitry Andric             void (*child)()) {
39668d75effSDimitry Andric   __lsan::ScopedInterceptorDisabler disabler;
39768d75effSDimitry Andric   // REAL(pthread_atfork) cannot be called due to symbol indirections at least
39868d75effSDimitry Andric   // on NetBSD
39968d75effSDimitry Andric   return _pthread_atfork(prepare, parent, child);
40068d75effSDimitry Andric }
40168d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK INTERCEPT_FUNCTION(pthread_atfork)
40268d75effSDimitry Andric #else
40368d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK
40468d75effSDimitry Andric #endif
40568d75effSDimitry Andric 
40668d75effSDimitry Andric #if SANITIZER_INTERCEPT_STRERROR
40768d75effSDimitry Andric INTERCEPTOR(char *, strerror, int errnum) {
40868d75effSDimitry Andric   __lsan::ScopedInterceptorDisabler disabler;
40968d75effSDimitry Andric   return REAL(strerror)(errnum);
41068d75effSDimitry Andric }
41168d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_STRERROR INTERCEPT_FUNCTION(strerror)
41268d75effSDimitry Andric #else
41368d75effSDimitry Andric #define LSAN_MAYBE_INTERCEPT_STRERROR
41468d75effSDimitry Andric #endif
41568d75effSDimitry Andric 
4165ffd83dbSDimitry Andric #if SANITIZER_POSIX
4175ffd83dbSDimitry Andric 
418*06c3fb27SDimitry Andric template <bool Detached>
419*06c3fb27SDimitry Andric static void *ThreadStartFunc(void *arg) {
420*06c3fb27SDimitry Andric   u32 parent_tid = (uptr)arg;
421*06c3fb27SDimitry Andric   uptr tid = ThreadCreate(parent_tid, Detached);
42268d75effSDimitry Andric   // Wait until the last iteration to maximize the chance that we are the last
42368d75effSDimitry Andric   // destructor to run.
42468d75effSDimitry Andric #if !SANITIZER_NETBSD && !SANITIZER_FREEBSD
42568d75effSDimitry Andric   if (pthread_setspecific(g_thread_finalize_key,
42668d75effSDimitry Andric                           (void*)GetPthreadDestructorIterations())) {
42768d75effSDimitry Andric     Report("LeakSanitizer: failed to set thread key.\n");
42868d75effSDimitry Andric     Die();
42968d75effSDimitry Andric   }
43068d75effSDimitry Andric #  endif
43168d75effSDimitry Andric   ThreadStart(tid, GetTid());
432*06c3fb27SDimitry Andric   auto self = GetThreadSelf();
433*06c3fb27SDimitry Andric   auto args = GetThreadArgRetval().GetArgs(self);
434*06c3fb27SDimitry Andric   void *retval = (*args.routine)(args.arg_retval);
435*06c3fb27SDimitry Andric   GetThreadArgRetval().Finish(self, retval);
436*06c3fb27SDimitry Andric   return retval;
43768d75effSDimitry Andric }
43868d75effSDimitry Andric 
43968d75effSDimitry Andric INTERCEPTOR(int, pthread_create, void *th, void *attr,
44068d75effSDimitry Andric             void *(*callback)(void *), void *param) {
44168d75effSDimitry Andric   ENSURE_LSAN_INITED;
44268d75effSDimitry Andric   EnsureMainThreadIDIsCorrect();
443*06c3fb27SDimitry Andric 
444*06c3fb27SDimitry Andric   bool detached = [attr]() {
445*06c3fb27SDimitry Andric     int d = 0;
446*06c3fb27SDimitry Andric     return attr && !pthread_attr_getdetachstate(attr, &d) && IsStateDetached(d);
447*06c3fb27SDimitry Andric   }();
448*06c3fb27SDimitry Andric 
44968d75effSDimitry Andric   __sanitizer_pthread_attr_t myattr;
45068d75effSDimitry Andric   if (!attr) {
45168d75effSDimitry Andric     pthread_attr_init(&myattr);
45268d75effSDimitry Andric     attr = &myattr;
45368d75effSDimitry Andric   }
45468d75effSDimitry Andric   AdjustStackSize(attr);
455*06c3fb27SDimitry Andric   uptr this_tid = GetCurrentThreadId();
456*06c3fb27SDimitry Andric   int result;
45768d75effSDimitry Andric   {
45868d75effSDimitry Andric     // Ignore all allocations made by pthread_create: thread stack/TLS may be
45968d75effSDimitry Andric     // stored by pthread for future reuse even after thread destruction, and
46068d75effSDimitry Andric     // the linked list it's stored in doesn't even hold valid pointers to the
46168d75effSDimitry Andric     // objects, the latter are calculated by obscure pointer arithmetic.
46268d75effSDimitry Andric     ScopedInterceptorDisabler disabler;
463*06c3fb27SDimitry Andric     GetThreadArgRetval().Create(detached, {callback, param}, [&]() -> uptr {
464*06c3fb27SDimitry Andric       result = REAL(pthread_create)(
465*06c3fb27SDimitry Andric           th, attr, detached ? ThreadStartFunc<true> : ThreadStartFunc<false>,
466*06c3fb27SDimitry Andric           (void *)this_tid);
467*06c3fb27SDimitry Andric       return result ? 0 : *(uptr *)(th);
468*06c3fb27SDimitry Andric     });
46968d75effSDimitry Andric   }
47068d75effSDimitry Andric   if (attr == &myattr)
47168d75effSDimitry Andric     pthread_attr_destroy(&myattr);
472*06c3fb27SDimitry Andric   return result;
47368d75effSDimitry Andric }
47468d75effSDimitry Andric 
475*06c3fb27SDimitry Andric INTERCEPTOR(int, pthread_join, void *thread, void **retval) {
476*06c3fb27SDimitry Andric   int result;
477*06c3fb27SDimitry Andric   GetThreadArgRetval().Join((uptr)thread, [&]() {
478*06c3fb27SDimitry Andric     result = REAL(pthread_join)(thread, retval);
479*06c3fb27SDimitry Andric     return !result;
480*06c3fb27SDimitry Andric   });
481*06c3fb27SDimitry Andric   return result;
4820eae32dcSDimitry Andric }
4830eae32dcSDimitry Andric 
484*06c3fb27SDimitry Andric INTERCEPTOR(int, pthread_detach, void *thread) {
485*06c3fb27SDimitry Andric   int result;
486*06c3fb27SDimitry Andric   GetThreadArgRetval().Detach((uptr)thread, [&]() {
487*06c3fb27SDimitry Andric     result = REAL(pthread_detach)(thread);
488*06c3fb27SDimitry Andric     return !result;
489*06c3fb27SDimitry Andric   });
490*06c3fb27SDimitry Andric   return result;
491*06c3fb27SDimitry Andric }
492*06c3fb27SDimitry Andric 
493*06c3fb27SDimitry Andric INTERCEPTOR(int, pthread_exit, void *retval) {
494*06c3fb27SDimitry Andric   GetThreadArgRetval().Finish(GetThreadSelf(), retval);
495*06c3fb27SDimitry Andric   return REAL(pthread_exit)(retval);
496*06c3fb27SDimitry Andric }
497*06c3fb27SDimitry Andric 
498*06c3fb27SDimitry Andric #  if SANITIZER_INTERCEPT_TRYJOIN
499*06c3fb27SDimitry Andric INTERCEPTOR(int, pthread_tryjoin_np, void *thread, void **ret) {
500*06c3fb27SDimitry Andric   int result;
501*06c3fb27SDimitry Andric   GetThreadArgRetval().Join((uptr)thread, [&]() {
502*06c3fb27SDimitry Andric     result = REAL(pthread_tryjoin_np)(thread, ret);
503*06c3fb27SDimitry Andric     return !result;
504*06c3fb27SDimitry Andric   });
505*06c3fb27SDimitry Andric   return result;
506*06c3fb27SDimitry Andric }
507*06c3fb27SDimitry Andric #    define LSAN_MAYBE_INTERCEPT_TRYJOIN INTERCEPT_FUNCTION(pthread_tryjoin_np)
508*06c3fb27SDimitry Andric #  else
509*06c3fb27SDimitry Andric #    define LSAN_MAYBE_INTERCEPT_TRYJOIN
510*06c3fb27SDimitry Andric #  endif  // SANITIZER_INTERCEPT_TRYJOIN
511*06c3fb27SDimitry Andric 
512*06c3fb27SDimitry Andric #  if SANITIZER_INTERCEPT_TIMEDJOIN
513*06c3fb27SDimitry Andric INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **ret,
514*06c3fb27SDimitry Andric             const struct timespec *abstime) {
515*06c3fb27SDimitry Andric   int result;
516*06c3fb27SDimitry Andric   GetThreadArgRetval().Join((uptr)thread, [&]() {
517*06c3fb27SDimitry Andric     result = REAL(pthread_timedjoin_np)(thread, ret, abstime);
518*06c3fb27SDimitry Andric     return !result;
519*06c3fb27SDimitry Andric   });
520*06c3fb27SDimitry Andric   return result;
521*06c3fb27SDimitry Andric }
522*06c3fb27SDimitry Andric #    define LSAN_MAYBE_INTERCEPT_TIMEDJOIN \
523*06c3fb27SDimitry Andric       INTERCEPT_FUNCTION(pthread_timedjoin_np)
524*06c3fb27SDimitry Andric #  else
525*06c3fb27SDimitry Andric #    define LSAN_MAYBE_INTERCEPT_TIMEDJOIN
526*06c3fb27SDimitry Andric #  endif  // SANITIZER_INTERCEPT_TIMEDJOIN
527*06c3fb27SDimitry Andric 
5280eae32dcSDimitry Andric DEFINE_REAL_PTHREAD_FUNCTIONS
5290eae32dcSDimitry Andric 
53068d75effSDimitry Andric INTERCEPTOR(void, _exit, int status) {
53168d75effSDimitry Andric   if (status == 0 && HasReportedLeaks()) status = common_flags()->exitcode;
53268d75effSDimitry Andric   REAL(_exit)(status);
53368d75effSDimitry Andric }
53468d75effSDimitry Andric 
53568d75effSDimitry Andric #define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name)
536*06c3fb27SDimitry Andric #define SIGNAL_INTERCEPTOR_ENTER() ENSURE_LSAN_INITED
53768d75effSDimitry Andric #include "sanitizer_common/sanitizer_signal_interceptors.inc"
53868d75effSDimitry Andric 
5395ffd83dbSDimitry Andric #endif  // SANITIZER_POSIX
5405ffd83dbSDimitry Andric 
54168d75effSDimitry Andric namespace __lsan {
54268d75effSDimitry Andric 
54368d75effSDimitry Andric void InitializeInterceptors() {
5445ffd83dbSDimitry Andric   // Fuchsia doesn't use interceptors that require any setup.
5455ffd83dbSDimitry Andric #if !SANITIZER_FUCHSIA
54668d75effSDimitry Andric   InitializeSignalInterceptors();
54768d75effSDimitry Andric 
54868d75effSDimitry Andric   INTERCEPT_FUNCTION(malloc);
54968d75effSDimitry Andric   INTERCEPT_FUNCTION(free);
55068d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_CFREE;
55168d75effSDimitry Andric   INTERCEPT_FUNCTION(calloc);
55268d75effSDimitry Andric   INTERCEPT_FUNCTION(realloc);
55368d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_MEMALIGN;
55468d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN;
55568d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC;
55668d75effSDimitry Andric   INTERCEPT_FUNCTION(posix_memalign);
55768d75effSDimitry Andric   INTERCEPT_FUNCTION(valloc);
55868d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_PVALLOC;
55968d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE;
56068d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_MALLINFO;
56168d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_MALLOPT;
56268d75effSDimitry Andric   INTERCEPT_FUNCTION(pthread_create);
5630eae32dcSDimitry Andric   INTERCEPT_FUNCTION(pthread_join);
564*06c3fb27SDimitry Andric   INTERCEPT_FUNCTION(pthread_detach);
565*06c3fb27SDimitry Andric   INTERCEPT_FUNCTION(pthread_exit);
566*06c3fb27SDimitry Andric   LSAN_MAYBE_INTERCEPT_TIMEDJOIN;
567*06c3fb27SDimitry Andric   LSAN_MAYBE_INTERCEPT_TRYJOIN;
56868d75effSDimitry Andric   INTERCEPT_FUNCTION(_exit);
56968d75effSDimitry Andric 
57068d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT__LWP_EXIT;
57168d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_THR_EXIT;
57268d75effSDimitry Andric 
57368d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT___CXA_ATEXIT;
57468d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_ATEXIT;
57568d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK;
57668d75effSDimitry Andric 
57768d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_STRERROR;
57868d75effSDimitry Andric 
57968d75effSDimitry Andric #if !SANITIZER_NETBSD && !SANITIZER_FREEBSD
58068d75effSDimitry Andric   if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) {
58168d75effSDimitry Andric     Report("LeakSanitizer: failed to create thread key.\n");
58268d75effSDimitry Andric     Die();
58368d75effSDimitry Andric   }
58468d75effSDimitry Andric #endif
5855ffd83dbSDimitry Andric 
5865ffd83dbSDimitry Andric #endif  // !SANITIZER_FUCHSIA
58768d75effSDimitry Andric }
58868d75effSDimitry Andric 
58968d75effSDimitry Andric } // namespace __lsan
590