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