xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/lsan/lsan_interceptors.cpp (revision 0eae32dcef82f6f06de6419a0d623d7def0cc8f6)
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 
7068d75effSDimitry Andric #if !SANITIZER_MAC
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 }
1195ffd83dbSDimitry Andric #endif  // !SANITIZER_MAC
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
20068d75effSDimitry Andric INTERCEPTOR(void, cfree, void *p) ALIAS(WRAPPER_NAME(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.
24568d75effSDimitry Andric #if !SANITIZER_MAC
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 
30468d75effSDimitry Andric #else  // SANITIZER_MAC
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 
32468d75effSDimitry Andric #endif  // !SANITIZER_MAC
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 
41868d75effSDimitry Andric struct ThreadParam {
41968d75effSDimitry Andric   void *(*callback)(void *arg);
42068d75effSDimitry Andric   void *param;
42168d75effSDimitry Andric   atomic_uintptr_t tid;
42268d75effSDimitry Andric };
42368d75effSDimitry Andric 
42468d75effSDimitry Andric extern "C" void *__lsan_thread_start_func(void *arg) {
42568d75effSDimitry Andric   ThreadParam *p = (ThreadParam*)arg;
42668d75effSDimitry Andric   void* (*callback)(void *arg) = p->callback;
42768d75effSDimitry Andric   void *param = p->param;
42868d75effSDimitry Andric   // Wait until the last iteration to maximize the chance that we are the last
42968d75effSDimitry Andric   // destructor to run.
43068d75effSDimitry Andric #if !SANITIZER_NETBSD && !SANITIZER_FREEBSD
43168d75effSDimitry Andric   if (pthread_setspecific(g_thread_finalize_key,
43268d75effSDimitry Andric                           (void*)GetPthreadDestructorIterations())) {
43368d75effSDimitry Andric     Report("LeakSanitizer: failed to set thread key.\n");
43468d75effSDimitry Andric     Die();
43568d75effSDimitry Andric   }
43668d75effSDimitry Andric #endif
43768d75effSDimitry Andric   int tid = 0;
43868d75effSDimitry Andric   while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0)
43968d75effSDimitry Andric     internal_sched_yield();
44068d75effSDimitry Andric   ThreadStart(tid, GetTid());
44168d75effSDimitry Andric   atomic_store(&p->tid, 0, memory_order_release);
44268d75effSDimitry Andric   return callback(param);
44368d75effSDimitry Andric }
44468d75effSDimitry Andric 
44568d75effSDimitry Andric INTERCEPTOR(int, pthread_create, void *th, void *attr,
44668d75effSDimitry Andric             void *(*callback)(void *), void *param) {
44768d75effSDimitry Andric   ENSURE_LSAN_INITED;
44868d75effSDimitry Andric   EnsureMainThreadIDIsCorrect();
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);
45568d75effSDimitry Andric   int detached = 0;
45668d75effSDimitry Andric   pthread_attr_getdetachstate(attr, &detached);
45768d75effSDimitry Andric   ThreadParam p;
45868d75effSDimitry Andric   p.callback = callback;
45968d75effSDimitry Andric   p.param = param;
46068d75effSDimitry Andric   atomic_store(&p.tid, 0, memory_order_relaxed);
46168d75effSDimitry Andric   int res;
46268d75effSDimitry Andric   {
46368d75effSDimitry Andric     // Ignore all allocations made by pthread_create: thread stack/TLS may be
46468d75effSDimitry Andric     // stored by pthread for future reuse even after thread destruction, and
46568d75effSDimitry Andric     // the linked list it's stored in doesn't even hold valid pointers to the
46668d75effSDimitry Andric     // objects, the latter are calculated by obscure pointer arithmetic.
46768d75effSDimitry Andric     ScopedInterceptorDisabler disabler;
46868d75effSDimitry Andric     res = REAL(pthread_create)(th, attr, __lsan_thread_start_func, &p);
46968d75effSDimitry Andric   }
47068d75effSDimitry Andric   if (res == 0) {
471349cc55cSDimitry Andric     int tid = ThreadCreate(GetCurrentThread(), IsStateDetached(detached));
472fe6060f1SDimitry Andric     CHECK_NE(tid, kMainTid);
47368d75effSDimitry Andric     atomic_store(&p.tid, tid, memory_order_release);
47468d75effSDimitry Andric     while (atomic_load(&p.tid, memory_order_acquire) != 0)
47568d75effSDimitry Andric       internal_sched_yield();
47668d75effSDimitry Andric   }
47768d75effSDimitry Andric   if (attr == &myattr)
47868d75effSDimitry Andric     pthread_attr_destroy(&myattr);
47968d75effSDimitry Andric   return res;
48068d75effSDimitry Andric }
48168d75effSDimitry Andric 
482*0eae32dcSDimitry Andric INTERCEPTOR(int, pthread_join, void *t, void **arg) {
483*0eae32dcSDimitry Andric   return REAL(pthread_join)(t, arg);
484*0eae32dcSDimitry Andric }
485*0eae32dcSDimitry Andric 
486*0eae32dcSDimitry Andric DEFINE_REAL_PTHREAD_FUNCTIONS
487*0eae32dcSDimitry Andric 
48868d75effSDimitry Andric INTERCEPTOR(void, _exit, int status) {
48968d75effSDimitry Andric   if (status == 0 && HasReportedLeaks()) status = common_flags()->exitcode;
49068d75effSDimitry Andric   REAL(_exit)(status);
49168d75effSDimitry Andric }
49268d75effSDimitry Andric 
49368d75effSDimitry Andric #define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name)
49468d75effSDimitry Andric #include "sanitizer_common/sanitizer_signal_interceptors.inc"
49568d75effSDimitry Andric 
4965ffd83dbSDimitry Andric #endif  // SANITIZER_POSIX
4975ffd83dbSDimitry Andric 
49868d75effSDimitry Andric namespace __lsan {
49968d75effSDimitry Andric 
50068d75effSDimitry Andric void InitializeInterceptors() {
5015ffd83dbSDimitry Andric   // Fuchsia doesn't use interceptors that require any setup.
5025ffd83dbSDimitry Andric #if !SANITIZER_FUCHSIA
50368d75effSDimitry Andric   InitializeSignalInterceptors();
50468d75effSDimitry Andric 
50568d75effSDimitry Andric   INTERCEPT_FUNCTION(malloc);
50668d75effSDimitry Andric   INTERCEPT_FUNCTION(free);
50768d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_CFREE;
50868d75effSDimitry Andric   INTERCEPT_FUNCTION(calloc);
50968d75effSDimitry Andric   INTERCEPT_FUNCTION(realloc);
51068d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_MEMALIGN;
51168d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN;
51268d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC;
51368d75effSDimitry Andric   INTERCEPT_FUNCTION(posix_memalign);
51468d75effSDimitry Andric   INTERCEPT_FUNCTION(valloc);
51568d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_PVALLOC;
51668d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE;
51768d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_MALLINFO;
51868d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_MALLOPT;
51968d75effSDimitry Andric   INTERCEPT_FUNCTION(pthread_create);
520*0eae32dcSDimitry Andric   INTERCEPT_FUNCTION(pthread_join);
52168d75effSDimitry Andric   INTERCEPT_FUNCTION(_exit);
52268d75effSDimitry Andric 
52368d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT__LWP_EXIT;
52468d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_THR_EXIT;
52568d75effSDimitry Andric 
52668d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT___CXA_ATEXIT;
52768d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_ATEXIT;
52868d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK;
52968d75effSDimitry Andric 
53068d75effSDimitry Andric   LSAN_MAYBE_INTERCEPT_STRERROR;
53168d75effSDimitry Andric 
53268d75effSDimitry Andric #if !SANITIZER_NETBSD && !SANITIZER_FREEBSD
53368d75effSDimitry Andric   if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) {
53468d75effSDimitry Andric     Report("LeakSanitizer: failed to create thread key.\n");
53568d75effSDimitry Andric     Die();
53668d75effSDimitry Andric   }
53768d75effSDimitry Andric #endif
5385ffd83dbSDimitry Andric 
5395ffd83dbSDimitry Andric #endif  // !SANITIZER_FUCHSIA
54068d75effSDimitry Andric }
54168d75effSDimitry Andric 
54268d75effSDimitry Andric } // namespace __lsan
543