Path: blob/main/contrib/llvm-project/compiler-rt/lib/lsan/lsan_interceptors.cpp
35233 views
//=-- lsan_interceptors.cpp -----------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file is a part of LeakSanitizer.9// Interceptors for standalone LSan.10//11//===----------------------------------------------------------------------===//1213#include "interception/interception.h"14#include "sanitizer_common/sanitizer_allocator.h"15#include "sanitizer_common/sanitizer_allocator_dlsym.h"16#include "sanitizer_common/sanitizer_allocator_report.h"17#include "sanitizer_common/sanitizer_atomic.h"18#include "sanitizer_common/sanitizer_common.h"19#include "sanitizer_common/sanitizer_flags.h"20#include "sanitizer_common/sanitizer_internal_defs.h"21#include "sanitizer_common/sanitizer_linux.h"22#include "sanitizer_common/sanitizer_platform_interceptors.h"23#include "sanitizer_common/sanitizer_platform_limits_netbsd.h"24#include "sanitizer_common/sanitizer_platform_limits_posix.h"25#if SANITIZER_POSIX26#include "sanitizer_common/sanitizer_posix.h"27#endif28#include "sanitizer_common/sanitizer_tls_get_addr.h"29#include "lsan.h"30#include "lsan_allocator.h"31#include "lsan_common.h"32#include "lsan_thread.h"3334#include <stddef.h>3536using namespace __lsan;3738extern "C" {39int pthread_attr_init(void *attr);40int pthread_attr_destroy(void *attr);41int pthread_attr_getdetachstate(void *attr, int *v);42int pthread_key_create(unsigned *key, void (*destructor)(void* v));43int pthread_setspecific(unsigned key, const void *v);44}4546struct DlsymAlloc : DlSymAllocator<DlsymAlloc> {47static bool UseImpl() { return lsan_init_is_running; }48static void OnAllocate(const void *ptr, uptr size) {49#if CAN_SANITIZE_LEAKS50// Suppress leaks from dlerror(). Previously dlsym hack on global array was51// used by leak sanitizer as a root region.52__lsan_register_root_region(ptr, size);53#endif54}55static void OnFree(const void *ptr, uptr size) {56#if CAN_SANITIZE_LEAKS57__lsan_unregister_root_region(ptr, size);58#endif59}60};6162///// Malloc/free interceptors. /////6364namespace std {65struct nothrow_t;66enum class align_val_t: size_t;67}6869#if !SANITIZER_APPLE70INTERCEPTOR(void*, malloc, uptr size) {71if (DlsymAlloc::Use())72return DlsymAlloc::Allocate(size);73ENSURE_LSAN_INITED;74GET_STACK_TRACE_MALLOC;75return lsan_malloc(size, stack);76}7778INTERCEPTOR(void, free, void *p) {79if (UNLIKELY(!p))80return;81if (DlsymAlloc::PointerIsMine(p))82return DlsymAlloc::Free(p);83ENSURE_LSAN_INITED;84lsan_free(p);85}8687INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {88if (DlsymAlloc::Use())89return DlsymAlloc::Callocate(nmemb, size);90ENSURE_LSAN_INITED;91GET_STACK_TRACE_MALLOC;92return lsan_calloc(nmemb, size, stack);93}9495INTERCEPTOR(void *, realloc, void *ptr, uptr size) {96if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr))97return DlsymAlloc::Realloc(ptr, size);98ENSURE_LSAN_INITED;99GET_STACK_TRACE_MALLOC;100return lsan_realloc(ptr, size, stack);101}102103INTERCEPTOR(void*, reallocarray, void *q, uptr nmemb, uptr size) {104ENSURE_LSAN_INITED;105GET_STACK_TRACE_MALLOC;106return lsan_reallocarray(q, nmemb, size, stack);107}108109INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {110ENSURE_LSAN_INITED;111GET_STACK_TRACE_MALLOC;112return lsan_posix_memalign(memptr, alignment, size, stack);113}114115INTERCEPTOR(void*, valloc, uptr size) {116ENSURE_LSAN_INITED;117GET_STACK_TRACE_MALLOC;118return lsan_valloc(size, stack);119}120#endif // !SANITIZER_APPLE121122#if SANITIZER_INTERCEPT_MEMALIGN123INTERCEPTOR(void*, memalign, uptr alignment, uptr size) {124ENSURE_LSAN_INITED;125GET_STACK_TRACE_MALLOC;126return lsan_memalign(alignment, size, stack);127}128#define LSAN_MAYBE_INTERCEPT_MEMALIGN INTERCEPT_FUNCTION(memalign)129#else130#define LSAN_MAYBE_INTERCEPT_MEMALIGN131#endif // SANITIZER_INTERCEPT_MEMALIGN132133#if SANITIZER_INTERCEPT___LIBC_MEMALIGN134INTERCEPTOR(void *, __libc_memalign, uptr alignment, uptr size) {135ENSURE_LSAN_INITED;136GET_STACK_TRACE_MALLOC;137void *res = lsan_memalign(alignment, size, stack);138DTLS_on_libc_memalign(res, size);139return res;140}141#define LSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN INTERCEPT_FUNCTION(__libc_memalign)142#else143#define LSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN144#endif // SANITIZER_INTERCEPT___LIBC_MEMALIGN145146#if SANITIZER_INTERCEPT_ALIGNED_ALLOC147INTERCEPTOR(void*, aligned_alloc, uptr alignment, uptr size) {148ENSURE_LSAN_INITED;149GET_STACK_TRACE_MALLOC;150return lsan_aligned_alloc(alignment, size, stack);151}152#define LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC INTERCEPT_FUNCTION(aligned_alloc)153#else154#define LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC155#endif156157#if SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE158INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {159ENSURE_LSAN_INITED;160return GetMallocUsableSize(ptr);161}162#define LSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE \163INTERCEPT_FUNCTION(malloc_usable_size)164#else165#define LSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE166#endif167168#if SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO169struct fake_mallinfo {170int x[10];171};172173INTERCEPTOR(struct fake_mallinfo, mallinfo, void) {174struct fake_mallinfo res;175internal_memset(&res, 0, sizeof(res));176return res;177}178#define LSAN_MAYBE_INTERCEPT_MALLINFO INTERCEPT_FUNCTION(mallinfo)179180INTERCEPTOR(int, mallopt, int cmd, int value) {181return 0;182}183#define LSAN_MAYBE_INTERCEPT_MALLOPT INTERCEPT_FUNCTION(mallopt)184#else185#define LSAN_MAYBE_INTERCEPT_MALLINFO186#define LSAN_MAYBE_INTERCEPT_MALLOPT187#endif // SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO188189#if SANITIZER_INTERCEPT_PVALLOC190INTERCEPTOR(void*, pvalloc, uptr size) {191ENSURE_LSAN_INITED;192GET_STACK_TRACE_MALLOC;193return lsan_pvalloc(size, stack);194}195#define LSAN_MAYBE_INTERCEPT_PVALLOC INTERCEPT_FUNCTION(pvalloc)196#else197#define LSAN_MAYBE_INTERCEPT_PVALLOC198#endif // SANITIZER_INTERCEPT_PVALLOC199200#if SANITIZER_INTERCEPT_CFREE201INTERCEPTOR(void, cfree, void *p) ALIAS(WRAP(free));202#define LSAN_MAYBE_INTERCEPT_CFREE INTERCEPT_FUNCTION(cfree)203#else204#define LSAN_MAYBE_INTERCEPT_CFREE205#endif // SANITIZER_INTERCEPT_CFREE206207#if SANITIZER_INTERCEPT_MCHECK_MPROBE208INTERCEPTOR(int, mcheck, void (*abortfunc)(int mstatus)) {209return 0;210}211212INTERCEPTOR(int, mcheck_pedantic, void (*abortfunc)(int mstatus)) {213return 0;214}215216INTERCEPTOR(int, mprobe, void *ptr) {217return 0;218}219#endif // SANITIZER_INTERCEPT_MCHECK_MPROBE220221222// TODO(alekseys): throw std::bad_alloc instead of dying on OOM.223#define OPERATOR_NEW_BODY(nothrow)\224ENSURE_LSAN_INITED;\225GET_STACK_TRACE_MALLOC;\226void *res = lsan_malloc(size, stack);\227if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\228return res;229#define OPERATOR_NEW_BODY_ALIGN(nothrow)\230ENSURE_LSAN_INITED;\231GET_STACK_TRACE_MALLOC;\232void *res = lsan_memalign((uptr)align, size, stack);\233if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\234return res;235236#define OPERATOR_DELETE_BODY\237ENSURE_LSAN_INITED;\238lsan_free(ptr);239240// On OS X it's not enough to just provide our own 'operator new' and241// 'operator delete' implementations, because they're going to be in the runtime242// dylib, and the main executable will depend on both the runtime dylib and243// libstdc++, each of has its implementation of new and delete.244// To make sure that C++ allocation/deallocation operators are overridden on245// OS X we need to intercept them using their mangled names.246#if !SANITIZER_APPLE247248INTERCEPTOR_ATTRIBUTE249void *operator new(size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); }250INTERCEPTOR_ATTRIBUTE251void *operator new[](size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); }252INTERCEPTOR_ATTRIBUTE253void *operator new(size_t size, std::nothrow_t const&)254{ OPERATOR_NEW_BODY(true /*nothrow*/); }255INTERCEPTOR_ATTRIBUTE256void *operator new[](size_t size, std::nothrow_t const&)257{ OPERATOR_NEW_BODY(true /*nothrow*/); }258INTERCEPTOR_ATTRIBUTE259void *operator new(size_t size, std::align_val_t align)260{ OPERATOR_NEW_BODY_ALIGN(false /*nothrow*/); }261INTERCEPTOR_ATTRIBUTE262void *operator new[](size_t size, std::align_val_t align)263{ OPERATOR_NEW_BODY_ALIGN(false /*nothrow*/); }264INTERCEPTOR_ATTRIBUTE265void *operator new(size_t size, std::align_val_t align, std::nothrow_t const&)266{ OPERATOR_NEW_BODY_ALIGN(true /*nothrow*/); }267INTERCEPTOR_ATTRIBUTE268void *operator new[](size_t size, std::align_val_t align, std::nothrow_t const&)269{ OPERATOR_NEW_BODY_ALIGN(true /*nothrow*/); }270271INTERCEPTOR_ATTRIBUTE272void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }273INTERCEPTOR_ATTRIBUTE274void operator delete[](void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }275INTERCEPTOR_ATTRIBUTE276void operator delete(void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY; }277INTERCEPTOR_ATTRIBUTE278void operator delete[](void *ptr, std::nothrow_t const &)279{ OPERATOR_DELETE_BODY; }280INTERCEPTOR_ATTRIBUTE281void operator delete(void *ptr, size_t size) NOEXCEPT282{ OPERATOR_DELETE_BODY; }283INTERCEPTOR_ATTRIBUTE284void operator delete[](void *ptr, size_t size) NOEXCEPT285{ OPERATOR_DELETE_BODY; }286INTERCEPTOR_ATTRIBUTE287void operator delete(void *ptr, std::align_val_t) NOEXCEPT288{ OPERATOR_DELETE_BODY; }289INTERCEPTOR_ATTRIBUTE290void operator delete[](void *ptr, std::align_val_t) NOEXCEPT291{ OPERATOR_DELETE_BODY; }292INTERCEPTOR_ATTRIBUTE293void operator delete(void *ptr, std::align_val_t, std::nothrow_t const&)294{ OPERATOR_DELETE_BODY; }295INTERCEPTOR_ATTRIBUTE296void operator delete[](void *ptr, std::align_val_t, std::nothrow_t const&)297{ OPERATOR_DELETE_BODY; }298INTERCEPTOR_ATTRIBUTE299void operator delete(void *ptr, size_t size, std::align_val_t) NOEXCEPT300{ OPERATOR_DELETE_BODY; }301INTERCEPTOR_ATTRIBUTE302void operator delete[](void *ptr, size_t size, std::align_val_t) NOEXCEPT303{ OPERATOR_DELETE_BODY; }304305#else // SANITIZER_APPLE306307INTERCEPTOR(void *, _Znwm, size_t size)308{ OPERATOR_NEW_BODY(false /*nothrow*/); }309INTERCEPTOR(void *, _Znam, size_t size)310{ OPERATOR_NEW_BODY(false /*nothrow*/); }311INTERCEPTOR(void *, _ZnwmRKSt9nothrow_t, size_t size, std::nothrow_t const&)312{ OPERATOR_NEW_BODY(true /*nothrow*/); }313INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&)314{ OPERATOR_NEW_BODY(true /*nothrow*/); }315316INTERCEPTOR(void, _ZdlPv, void *ptr)317{ OPERATOR_DELETE_BODY; }318INTERCEPTOR(void, _ZdaPv, void *ptr)319{ OPERATOR_DELETE_BODY; }320INTERCEPTOR(void, _ZdlPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&)321{ OPERATOR_DELETE_BODY; }322INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&)323{ OPERATOR_DELETE_BODY; }324325#endif // !SANITIZER_APPLE326327328///// Thread initialization and finalization. /////329330#if !SANITIZER_NETBSD && !SANITIZER_FREEBSD && !SANITIZER_FUCHSIA331static unsigned g_thread_finalize_key;332333static void thread_finalize(void *v) {334uptr iter = (uptr)v;335if (iter > 1) {336if (pthread_setspecific(g_thread_finalize_key, (void*)(iter - 1))) {337Report("LeakSanitizer: failed to set thread key.\n");338Die();339}340return;341}342ThreadFinish();343}344#endif345346#if SANITIZER_NETBSD347INTERCEPTOR(void, _lwp_exit) {348ENSURE_LSAN_INITED;349ThreadFinish();350REAL(_lwp_exit)();351}352#define LSAN_MAYBE_INTERCEPT__LWP_EXIT INTERCEPT_FUNCTION(_lwp_exit)353#else354#define LSAN_MAYBE_INTERCEPT__LWP_EXIT355#endif356357#if SANITIZER_INTERCEPT_THR_EXIT358INTERCEPTOR(void, thr_exit, tid_t *state) {359ENSURE_LSAN_INITED;360ThreadFinish();361REAL(thr_exit)(state);362}363#define LSAN_MAYBE_INTERCEPT_THR_EXIT INTERCEPT_FUNCTION(thr_exit)364#else365#define LSAN_MAYBE_INTERCEPT_THR_EXIT366#endif367368#if SANITIZER_INTERCEPT___CXA_ATEXIT369INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,370void *dso_handle) {371__lsan::ScopedInterceptorDisabler disabler;372return REAL(__cxa_atexit)(func, arg, dso_handle);373}374#define LSAN_MAYBE_INTERCEPT___CXA_ATEXIT INTERCEPT_FUNCTION(__cxa_atexit)375#else376#define LSAN_MAYBE_INTERCEPT___CXA_ATEXIT377#endif378379#if SANITIZER_INTERCEPT_ATEXIT380INTERCEPTOR(int, atexit, void (*f)()) {381__lsan::ScopedInterceptorDisabler disabler;382return REAL(__cxa_atexit)((void (*)(void *a))f, 0, 0);383}384#define LSAN_MAYBE_INTERCEPT_ATEXIT INTERCEPT_FUNCTION(atexit)385#else386#define LSAN_MAYBE_INTERCEPT_ATEXIT387#endif388389#if SANITIZER_INTERCEPT_PTHREAD_ATFORK390extern "C" {391extern int _pthread_atfork(void (*prepare)(), void (*parent)(),392void (*child)());393}394395INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(),396void (*child)()) {397__lsan::ScopedInterceptorDisabler disabler;398// REAL(pthread_atfork) cannot be called due to symbol indirections at least399// on NetBSD400return _pthread_atfork(prepare, parent, child);401}402#define LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK INTERCEPT_FUNCTION(pthread_atfork)403#else404#define LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK405#endif406407#if SANITIZER_INTERCEPT_STRERROR408INTERCEPTOR(char *, strerror, int errnum) {409__lsan::ScopedInterceptorDisabler disabler;410return REAL(strerror)(errnum);411}412#define LSAN_MAYBE_INTERCEPT_STRERROR INTERCEPT_FUNCTION(strerror)413#else414#define LSAN_MAYBE_INTERCEPT_STRERROR415#endif416417#if SANITIZER_POSIX418419template <bool Detached>420static void *ThreadStartFunc(void *arg) {421u32 parent_tid = (uptr)arg;422uptr tid = ThreadCreate(parent_tid, Detached);423// Wait until the last iteration to maximize the chance that we are the last424// destructor to run.425#if !SANITIZER_NETBSD && !SANITIZER_FREEBSD426if (pthread_setspecific(g_thread_finalize_key,427(void*)GetPthreadDestructorIterations())) {428Report("LeakSanitizer: failed to set thread key.\n");429Die();430}431# endif432ThreadStart(tid, GetTid());433auto self = GetThreadSelf();434auto args = GetThreadArgRetval().GetArgs(self);435void *retval = (*args.routine)(args.arg_retval);436GetThreadArgRetval().Finish(self, retval);437return retval;438}439440INTERCEPTOR(int, pthread_create, void *th, void *attr,441void *(*callback)(void *), void *param) {442ENSURE_LSAN_INITED;443EnsureMainThreadIDIsCorrect();444445bool detached = [attr]() {446int d = 0;447return attr && !pthread_attr_getdetachstate(attr, &d) && IsStateDetached(d);448}();449450__sanitizer_pthread_attr_t myattr;451if (!attr) {452pthread_attr_init(&myattr);453attr = &myattr;454}455AdjustStackSize(attr);456uptr this_tid = GetCurrentThreadId();457int result;458{459// Ignore all allocations made by pthread_create: thread stack/TLS may be460// stored by pthread for future reuse even after thread destruction, and461// the linked list it's stored in doesn't even hold valid pointers to the462// objects, the latter are calculated by obscure pointer arithmetic.463ScopedInterceptorDisabler disabler;464GetThreadArgRetval().Create(detached, {callback, param}, [&]() -> uptr {465result = REAL(pthread_create)(466th, attr, detached ? ThreadStartFunc<true> : ThreadStartFunc<false>,467(void *)this_tid);468return result ? 0 : *(uptr *)(th);469});470}471if (attr == &myattr)472pthread_attr_destroy(&myattr);473return result;474}475476INTERCEPTOR(int, pthread_join, void *thread, void **retval) {477int result;478GetThreadArgRetval().Join((uptr)thread, [&]() {479result = REAL(pthread_join)(thread, retval);480return !result;481});482return result;483}484485INTERCEPTOR(int, pthread_detach, void *thread) {486int result;487GetThreadArgRetval().Detach((uptr)thread, [&]() {488result = REAL(pthread_detach)(thread);489return !result;490});491return result;492}493494INTERCEPTOR(void, pthread_exit, void *retval) {495GetThreadArgRetval().Finish(GetThreadSelf(), retval);496REAL(pthread_exit)(retval);497}498499# if SANITIZER_INTERCEPT_TRYJOIN500INTERCEPTOR(int, pthread_tryjoin_np, void *thread, void **ret) {501int result;502GetThreadArgRetval().Join((uptr)thread, [&]() {503result = REAL(pthread_tryjoin_np)(thread, ret);504return !result;505});506return result;507}508# define LSAN_MAYBE_INTERCEPT_TRYJOIN INTERCEPT_FUNCTION(pthread_tryjoin_np)509# else510# define LSAN_MAYBE_INTERCEPT_TRYJOIN511# endif // SANITIZER_INTERCEPT_TRYJOIN512513# if SANITIZER_INTERCEPT_TIMEDJOIN514INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **ret,515const struct timespec *abstime) {516int result;517GetThreadArgRetval().Join((uptr)thread, [&]() {518result = REAL(pthread_timedjoin_np)(thread, ret, abstime);519return !result;520});521return result;522}523# define LSAN_MAYBE_INTERCEPT_TIMEDJOIN \524INTERCEPT_FUNCTION(pthread_timedjoin_np)525# else526# define LSAN_MAYBE_INTERCEPT_TIMEDJOIN527# endif // SANITIZER_INTERCEPT_TIMEDJOIN528529DEFINE_INTERNAL_PTHREAD_FUNCTIONS530531INTERCEPTOR(void, _exit, int status) {532if (status == 0 && HasReportedLeaks()) status = common_flags()->exitcode;533REAL(_exit)(status);534}535536#define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name)537#define SIGNAL_INTERCEPTOR_ENTER() ENSURE_LSAN_INITED538#include "sanitizer_common/sanitizer_signal_interceptors.inc"539540#endif // SANITIZER_POSIX541542namespace __lsan {543544void InitializeInterceptors() {545// Fuchsia doesn't use interceptors that require any setup.546#if !SANITIZER_FUCHSIA547__interception::DoesNotSupportStaticLinking();548InitializeSignalInterceptors();549550INTERCEPT_FUNCTION(malloc);551INTERCEPT_FUNCTION(free);552LSAN_MAYBE_INTERCEPT_CFREE;553INTERCEPT_FUNCTION(calloc);554INTERCEPT_FUNCTION(realloc);555LSAN_MAYBE_INTERCEPT_MEMALIGN;556LSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN;557LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC;558INTERCEPT_FUNCTION(posix_memalign);559INTERCEPT_FUNCTION(valloc);560LSAN_MAYBE_INTERCEPT_PVALLOC;561LSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE;562LSAN_MAYBE_INTERCEPT_MALLINFO;563LSAN_MAYBE_INTERCEPT_MALLOPT;564INTERCEPT_FUNCTION(pthread_create);565INTERCEPT_FUNCTION(pthread_join);566INTERCEPT_FUNCTION(pthread_detach);567INTERCEPT_FUNCTION(pthread_exit);568LSAN_MAYBE_INTERCEPT_TIMEDJOIN;569LSAN_MAYBE_INTERCEPT_TRYJOIN;570INTERCEPT_FUNCTION(_exit);571572LSAN_MAYBE_INTERCEPT__LWP_EXIT;573LSAN_MAYBE_INTERCEPT_THR_EXIT;574575LSAN_MAYBE_INTERCEPT___CXA_ATEXIT;576LSAN_MAYBE_INTERCEPT_ATEXIT;577LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK;578579LSAN_MAYBE_INTERCEPT_STRERROR;580581#if !SANITIZER_NETBSD && !SANITIZER_FREEBSD582if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) {583Report("LeakSanitizer: failed to create thread key.\n");584Die();585}586#endif587588#endif // !SANITIZER_FUCHSIA589}590591} // namespace __lsan592593594