xref: /freebsd/contrib/llvm-project/compiler-rt/lib/lsan/lsan_interceptors.cpp (revision dc318a4ffabcbfa23bb56a33403aad36e6de30af)
1 //=-- lsan_interceptors.cpp -----------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file is a part of LeakSanitizer.
10 // Interceptors for standalone LSan.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "interception/interception.h"
15 #include "sanitizer_common/sanitizer_allocator.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_POSIX
26 #include "sanitizer_common/sanitizer_posix.h"
27 #endif
28 #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"
33 
34 #include <stddef.h>
35 
36 using namespace __lsan;
37 
38 extern "C" {
39 int pthread_attr_init(void *attr);
40 int pthread_attr_destroy(void *attr);
41 int pthread_attr_getdetachstate(void *attr, int *v);
42 int pthread_key_create(unsigned *key, void (*destructor)(void* v));
43 int pthread_setspecific(unsigned key, const void *v);
44 }
45 
46 ///// Malloc/free interceptors. /////
47 
48 namespace std {
49   struct nothrow_t;
50   enum class align_val_t: size_t;
51 }
52 
53 #if !SANITIZER_MAC
54 INTERCEPTOR(void*, malloc, uptr size) {
55   ENSURE_LSAN_INITED;
56   GET_STACK_TRACE_MALLOC;
57   return lsan_malloc(size, stack);
58 }
59 
60 INTERCEPTOR(void, free, void *p) {
61   ENSURE_LSAN_INITED;
62   lsan_free(p);
63 }
64 
65 INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
66   // This hack is not required for Fuchsia because there are no dlsym calls
67   // involved in setting up interceptors.
68 #if !SANITIZER_FUCHSIA
69   if (lsan_init_is_running) {
70     // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
71     const uptr kCallocPoolSize = 1024;
72     static uptr calloc_memory_for_dlsym[kCallocPoolSize];
73     static uptr allocated;
74     uptr size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize;
75     void *mem = (void*)&calloc_memory_for_dlsym[allocated];
76     allocated += size_in_words;
77     CHECK(allocated < kCallocPoolSize);
78     return mem;
79   }
80 #endif  // !SANITIZER_FUCHSIA
81   ENSURE_LSAN_INITED;
82   GET_STACK_TRACE_MALLOC;
83   return lsan_calloc(nmemb, size, stack);
84 }
85 
86 INTERCEPTOR(void*, realloc, void *q, uptr size) {
87   ENSURE_LSAN_INITED;
88   GET_STACK_TRACE_MALLOC;
89   return lsan_realloc(q, size, stack);
90 }
91 
92 INTERCEPTOR(void*, reallocarray, void *q, uptr nmemb, uptr size) {
93   ENSURE_LSAN_INITED;
94   GET_STACK_TRACE_MALLOC;
95   return lsan_reallocarray(q, nmemb, size, stack);
96 }
97 
98 INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
99   ENSURE_LSAN_INITED;
100   GET_STACK_TRACE_MALLOC;
101   return lsan_posix_memalign(memptr, alignment, size, stack);
102 }
103 
104 INTERCEPTOR(void*, valloc, uptr size) {
105   ENSURE_LSAN_INITED;
106   GET_STACK_TRACE_MALLOC;
107   return lsan_valloc(size, stack);
108 }
109 #endif  // !SANITIZER_MAC
110 
111 #if SANITIZER_INTERCEPT_MEMALIGN
112 INTERCEPTOR(void*, memalign, uptr alignment, uptr size) {
113   ENSURE_LSAN_INITED;
114   GET_STACK_TRACE_MALLOC;
115   return lsan_memalign(alignment, size, stack);
116 }
117 #define LSAN_MAYBE_INTERCEPT_MEMALIGN INTERCEPT_FUNCTION(memalign)
118 
119 INTERCEPTOR(void *, __libc_memalign, uptr alignment, uptr size) {
120   ENSURE_LSAN_INITED;
121   GET_STACK_TRACE_MALLOC;
122   void *res = lsan_memalign(alignment, size, stack);
123   DTLS_on_libc_memalign(res, size);
124   return res;
125 }
126 #define LSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN INTERCEPT_FUNCTION(__libc_memalign)
127 #else
128 #define LSAN_MAYBE_INTERCEPT_MEMALIGN
129 #define LSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN
130 #endif // SANITIZER_INTERCEPT_MEMALIGN
131 
132 #if SANITIZER_INTERCEPT_ALIGNED_ALLOC
133 INTERCEPTOR(void*, aligned_alloc, uptr alignment, uptr size) {
134   ENSURE_LSAN_INITED;
135   GET_STACK_TRACE_MALLOC;
136   return lsan_aligned_alloc(alignment, size, stack);
137 }
138 #define LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC INTERCEPT_FUNCTION(aligned_alloc)
139 #else
140 #define LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC
141 #endif
142 
143 #if SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE
144 INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
145   ENSURE_LSAN_INITED;
146   return GetMallocUsableSize(ptr);
147 }
148 #define LSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE \
149         INTERCEPT_FUNCTION(malloc_usable_size)
150 #else
151 #define LSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE
152 #endif
153 
154 #if SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO
155 struct fake_mallinfo {
156   int x[10];
157 };
158 
159 INTERCEPTOR(struct fake_mallinfo, mallinfo, void) {
160   struct fake_mallinfo res;
161   internal_memset(&res, 0, sizeof(res));
162   return res;
163 }
164 #define LSAN_MAYBE_INTERCEPT_MALLINFO INTERCEPT_FUNCTION(mallinfo)
165 
166 INTERCEPTOR(int, mallopt, int cmd, int value) {
167   return 0;
168 }
169 #define LSAN_MAYBE_INTERCEPT_MALLOPT INTERCEPT_FUNCTION(mallopt)
170 #else
171 #define LSAN_MAYBE_INTERCEPT_MALLINFO
172 #define LSAN_MAYBE_INTERCEPT_MALLOPT
173 #endif // SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO
174 
175 #if SANITIZER_INTERCEPT_PVALLOC
176 INTERCEPTOR(void*, pvalloc, uptr size) {
177   ENSURE_LSAN_INITED;
178   GET_STACK_TRACE_MALLOC;
179   return lsan_pvalloc(size, stack);
180 }
181 #define LSAN_MAYBE_INTERCEPT_PVALLOC INTERCEPT_FUNCTION(pvalloc)
182 #else
183 #define LSAN_MAYBE_INTERCEPT_PVALLOC
184 #endif // SANITIZER_INTERCEPT_PVALLOC
185 
186 #if SANITIZER_INTERCEPT_CFREE
187 INTERCEPTOR(void, cfree, void *p) ALIAS(WRAPPER_NAME(free));
188 #define LSAN_MAYBE_INTERCEPT_CFREE INTERCEPT_FUNCTION(cfree)
189 #else
190 #define LSAN_MAYBE_INTERCEPT_CFREE
191 #endif // SANITIZER_INTERCEPT_CFREE
192 
193 #if SANITIZER_INTERCEPT_MCHECK_MPROBE
194 INTERCEPTOR(int, mcheck, void (*abortfunc)(int mstatus)) {
195   return 0;
196 }
197 
198 INTERCEPTOR(int, mcheck_pedantic, void (*abortfunc)(int mstatus)) {
199   return 0;
200 }
201 
202 INTERCEPTOR(int, mprobe, void *ptr) {
203   return 0;
204 }
205 #endif // SANITIZER_INTERCEPT_MCHECK_MPROBE
206 
207 
208 // TODO(alekseys): throw std::bad_alloc instead of dying on OOM.
209 #define OPERATOR_NEW_BODY(nothrow)\
210   ENSURE_LSAN_INITED;\
211   GET_STACK_TRACE_MALLOC;\
212   void *res = lsan_malloc(size, stack);\
213   if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\
214   return res;
215 #define OPERATOR_NEW_BODY_ALIGN(nothrow)\
216   ENSURE_LSAN_INITED;\
217   GET_STACK_TRACE_MALLOC;\
218   void *res = lsan_memalign((uptr)align, size, stack);\
219   if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\
220   return res;
221 
222 #define OPERATOR_DELETE_BODY\
223   ENSURE_LSAN_INITED;\
224   lsan_free(ptr);
225 
226 // On OS X it's not enough to just provide our own 'operator new' and
227 // 'operator delete' implementations, because they're going to be in the runtime
228 // dylib, and the main executable will depend on both the runtime dylib and
229 // libstdc++, each of has its implementation of new and delete.
230 // To make sure that C++ allocation/deallocation operators are overridden on
231 // OS X we need to intercept them using their mangled names.
232 #if !SANITIZER_MAC
233 
234 INTERCEPTOR_ATTRIBUTE
235 void *operator new(size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); }
236 INTERCEPTOR_ATTRIBUTE
237 void *operator new[](size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); }
238 INTERCEPTOR_ATTRIBUTE
239 void *operator new(size_t size, std::nothrow_t const&)
240 { OPERATOR_NEW_BODY(true /*nothrow*/); }
241 INTERCEPTOR_ATTRIBUTE
242 void *operator new[](size_t size, std::nothrow_t const&)
243 { OPERATOR_NEW_BODY(true /*nothrow*/); }
244 INTERCEPTOR_ATTRIBUTE
245 void *operator new(size_t size, std::align_val_t align)
246 { OPERATOR_NEW_BODY_ALIGN(false /*nothrow*/); }
247 INTERCEPTOR_ATTRIBUTE
248 void *operator new[](size_t size, std::align_val_t align)
249 { OPERATOR_NEW_BODY_ALIGN(false /*nothrow*/); }
250 INTERCEPTOR_ATTRIBUTE
251 void *operator new(size_t size, std::align_val_t align, std::nothrow_t const&)
252 { OPERATOR_NEW_BODY_ALIGN(true /*nothrow*/); }
253 INTERCEPTOR_ATTRIBUTE
254 void *operator new[](size_t size, std::align_val_t align, std::nothrow_t const&)
255 { OPERATOR_NEW_BODY_ALIGN(true /*nothrow*/); }
256 
257 INTERCEPTOR_ATTRIBUTE
258 void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
259 INTERCEPTOR_ATTRIBUTE
260 void operator delete[](void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
261 INTERCEPTOR_ATTRIBUTE
262 void operator delete(void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY; }
263 INTERCEPTOR_ATTRIBUTE
264 void operator delete[](void *ptr, std::nothrow_t const &)
265 { OPERATOR_DELETE_BODY; }
266 INTERCEPTOR_ATTRIBUTE
267 void operator delete(void *ptr, size_t size) NOEXCEPT
268 { OPERATOR_DELETE_BODY; }
269 INTERCEPTOR_ATTRIBUTE
270 void operator delete[](void *ptr, size_t size) NOEXCEPT
271 { OPERATOR_DELETE_BODY; }
272 INTERCEPTOR_ATTRIBUTE
273 void operator delete(void *ptr, std::align_val_t) NOEXCEPT
274 { OPERATOR_DELETE_BODY; }
275 INTERCEPTOR_ATTRIBUTE
276 void operator delete[](void *ptr, std::align_val_t) NOEXCEPT
277 { OPERATOR_DELETE_BODY; }
278 INTERCEPTOR_ATTRIBUTE
279 void operator delete(void *ptr, std::align_val_t, std::nothrow_t const&)
280 { OPERATOR_DELETE_BODY; }
281 INTERCEPTOR_ATTRIBUTE
282 void operator delete[](void *ptr, std::align_val_t, std::nothrow_t const&)
283 { OPERATOR_DELETE_BODY; }
284 INTERCEPTOR_ATTRIBUTE
285 void operator delete(void *ptr, size_t size, std::align_val_t) NOEXCEPT
286 { OPERATOR_DELETE_BODY; }
287 INTERCEPTOR_ATTRIBUTE
288 void operator delete[](void *ptr, size_t size, std::align_val_t) NOEXCEPT
289 { OPERATOR_DELETE_BODY; }
290 
291 #else  // SANITIZER_MAC
292 
293 INTERCEPTOR(void *, _Znwm, size_t size)
294 { OPERATOR_NEW_BODY(false /*nothrow*/); }
295 INTERCEPTOR(void *, _Znam, size_t size)
296 { OPERATOR_NEW_BODY(false /*nothrow*/); }
297 INTERCEPTOR(void *, _ZnwmRKSt9nothrow_t, size_t size, std::nothrow_t const&)
298 { OPERATOR_NEW_BODY(true /*nothrow*/); }
299 INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&)
300 { OPERATOR_NEW_BODY(true /*nothrow*/); }
301 
302 INTERCEPTOR(void, _ZdlPv, void *ptr)
303 { OPERATOR_DELETE_BODY; }
304 INTERCEPTOR(void, _ZdaPv, void *ptr)
305 { OPERATOR_DELETE_BODY; }
306 INTERCEPTOR(void, _ZdlPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&)
307 { OPERATOR_DELETE_BODY; }
308 INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&)
309 { OPERATOR_DELETE_BODY; }
310 
311 #endif  // !SANITIZER_MAC
312 
313 
314 ///// Thread initialization and finalization. /////
315 
316 #if !SANITIZER_NETBSD && !SANITIZER_FREEBSD && !SANITIZER_FUCHSIA
317 static unsigned g_thread_finalize_key;
318 
319 static void thread_finalize(void *v) {
320   uptr iter = (uptr)v;
321   if (iter > 1) {
322     if (pthread_setspecific(g_thread_finalize_key, (void*)(iter - 1))) {
323       Report("LeakSanitizer: failed to set thread key.\n");
324       Die();
325     }
326     return;
327   }
328   ThreadFinish();
329 }
330 #endif
331 
332 #if SANITIZER_NETBSD
333 INTERCEPTOR(void, _lwp_exit) {
334   ENSURE_LSAN_INITED;
335   ThreadFinish();
336   REAL(_lwp_exit)();
337 }
338 #define LSAN_MAYBE_INTERCEPT__LWP_EXIT INTERCEPT_FUNCTION(_lwp_exit)
339 #else
340 #define LSAN_MAYBE_INTERCEPT__LWP_EXIT
341 #endif
342 
343 #if SANITIZER_INTERCEPT_THR_EXIT
344 INTERCEPTOR(void, thr_exit, tid_t *state) {
345   ENSURE_LSAN_INITED;
346   ThreadFinish();
347   REAL(thr_exit)(state);
348 }
349 #define LSAN_MAYBE_INTERCEPT_THR_EXIT INTERCEPT_FUNCTION(thr_exit)
350 #else
351 #define LSAN_MAYBE_INTERCEPT_THR_EXIT
352 #endif
353 
354 #if SANITIZER_INTERCEPT___CXA_ATEXIT
355 INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
356             void *dso_handle) {
357   __lsan::ScopedInterceptorDisabler disabler;
358   return REAL(__cxa_atexit)(func, arg, dso_handle);
359 }
360 #define LSAN_MAYBE_INTERCEPT___CXA_ATEXIT INTERCEPT_FUNCTION(__cxa_atexit)
361 #else
362 #define LSAN_MAYBE_INTERCEPT___CXA_ATEXIT
363 #endif
364 
365 #if SANITIZER_INTERCEPT_ATEXIT
366 INTERCEPTOR(int, atexit, void (*f)()) {
367   __lsan::ScopedInterceptorDisabler disabler;
368   return REAL(__cxa_atexit)((void (*)(void *a))f, 0, 0);
369 }
370 #define LSAN_MAYBE_INTERCEPT_ATEXIT INTERCEPT_FUNCTION(atexit)
371 #else
372 #define LSAN_MAYBE_INTERCEPT_ATEXIT
373 #endif
374 
375 #if SANITIZER_INTERCEPT_PTHREAD_ATFORK
376 extern "C" {
377 extern int _pthread_atfork(void (*prepare)(), void (*parent)(),
378                            void (*child)());
379 };
380 
381 INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(),
382             void (*child)()) {
383   __lsan::ScopedInterceptorDisabler disabler;
384   // REAL(pthread_atfork) cannot be called due to symbol indirections at least
385   // on NetBSD
386   return _pthread_atfork(prepare, parent, child);
387 }
388 #define LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK INTERCEPT_FUNCTION(pthread_atfork)
389 #else
390 #define LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK
391 #endif
392 
393 #if SANITIZER_INTERCEPT_STRERROR
394 INTERCEPTOR(char *, strerror, int errnum) {
395   __lsan::ScopedInterceptorDisabler disabler;
396   return REAL(strerror)(errnum);
397 }
398 #define LSAN_MAYBE_INTERCEPT_STRERROR INTERCEPT_FUNCTION(strerror)
399 #else
400 #define LSAN_MAYBE_INTERCEPT_STRERROR
401 #endif
402 
403 #if SANITIZER_POSIX
404 
405 struct ThreadParam {
406   void *(*callback)(void *arg);
407   void *param;
408   atomic_uintptr_t tid;
409 };
410 
411 extern "C" void *__lsan_thread_start_func(void *arg) {
412   ThreadParam *p = (ThreadParam*)arg;
413   void* (*callback)(void *arg) = p->callback;
414   void *param = p->param;
415   // Wait until the last iteration to maximize the chance that we are the last
416   // destructor to run.
417 #if !SANITIZER_NETBSD && !SANITIZER_FREEBSD
418   if (pthread_setspecific(g_thread_finalize_key,
419                           (void*)GetPthreadDestructorIterations())) {
420     Report("LeakSanitizer: failed to set thread key.\n");
421     Die();
422   }
423 #endif
424   int tid = 0;
425   while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0)
426     internal_sched_yield();
427   ThreadStart(tid, GetTid());
428   atomic_store(&p->tid, 0, memory_order_release);
429   return callback(param);
430 }
431 
432 INTERCEPTOR(int, pthread_create, void *th, void *attr,
433             void *(*callback)(void *), void *param) {
434   ENSURE_LSAN_INITED;
435   EnsureMainThreadIDIsCorrect();
436   __sanitizer_pthread_attr_t myattr;
437   if (!attr) {
438     pthread_attr_init(&myattr);
439     attr = &myattr;
440   }
441   AdjustStackSize(attr);
442   int detached = 0;
443   pthread_attr_getdetachstate(attr, &detached);
444   ThreadParam p;
445   p.callback = callback;
446   p.param = param;
447   atomic_store(&p.tid, 0, memory_order_relaxed);
448   int res;
449   {
450     // Ignore all allocations made by pthread_create: thread stack/TLS may be
451     // stored by pthread for future reuse even after thread destruction, and
452     // the linked list it's stored in doesn't even hold valid pointers to the
453     // objects, the latter are calculated by obscure pointer arithmetic.
454     ScopedInterceptorDisabler disabler;
455     res = REAL(pthread_create)(th, attr, __lsan_thread_start_func, &p);
456   }
457   if (res == 0) {
458     int tid = ThreadCreate(GetCurrentThread(), *(uptr *)th,
459                            IsStateDetached(detached));
460     CHECK_NE(tid, 0);
461     atomic_store(&p.tid, tid, memory_order_release);
462     while (atomic_load(&p.tid, memory_order_acquire) != 0)
463       internal_sched_yield();
464   }
465   if (attr == &myattr)
466     pthread_attr_destroy(&myattr);
467   return res;
468 }
469 
470 INTERCEPTOR(int, pthread_join, void *th, void **ret) {
471   ENSURE_LSAN_INITED;
472   int tid = ThreadTid((uptr)th);
473   int res = REAL(pthread_join)(th, ret);
474   if (res == 0)
475     ThreadJoin(tid);
476   return res;
477 }
478 
479 INTERCEPTOR(void, _exit, int status) {
480   if (status == 0 && HasReportedLeaks()) status = common_flags()->exitcode;
481   REAL(_exit)(status);
482 }
483 
484 #define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name)
485 #include "sanitizer_common/sanitizer_signal_interceptors.inc"
486 
487 #endif  // SANITIZER_POSIX
488 
489 namespace __lsan {
490 
491 void InitializeInterceptors() {
492   // Fuchsia doesn't use interceptors that require any setup.
493 #if !SANITIZER_FUCHSIA
494   InitializeSignalInterceptors();
495 
496   INTERCEPT_FUNCTION(malloc);
497   INTERCEPT_FUNCTION(free);
498   LSAN_MAYBE_INTERCEPT_CFREE;
499   INTERCEPT_FUNCTION(calloc);
500   INTERCEPT_FUNCTION(realloc);
501   LSAN_MAYBE_INTERCEPT_MEMALIGN;
502   LSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN;
503   LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC;
504   INTERCEPT_FUNCTION(posix_memalign);
505   INTERCEPT_FUNCTION(valloc);
506   LSAN_MAYBE_INTERCEPT_PVALLOC;
507   LSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE;
508   LSAN_MAYBE_INTERCEPT_MALLINFO;
509   LSAN_MAYBE_INTERCEPT_MALLOPT;
510   INTERCEPT_FUNCTION(pthread_create);
511   INTERCEPT_FUNCTION(pthread_join);
512   INTERCEPT_FUNCTION(_exit);
513 
514   LSAN_MAYBE_INTERCEPT__LWP_EXIT;
515   LSAN_MAYBE_INTERCEPT_THR_EXIT;
516 
517   LSAN_MAYBE_INTERCEPT___CXA_ATEXIT;
518   LSAN_MAYBE_INTERCEPT_ATEXIT;
519   LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK;
520 
521   LSAN_MAYBE_INTERCEPT_STRERROR;
522 
523 #if !SANITIZER_NETBSD && !SANITIZER_FREEBSD
524   if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) {
525     Report("LeakSanitizer: failed to create thread key.\n");
526     Die();
527   }
528 #endif
529 
530 #endif  // !SANITIZER_FUCHSIA
531 }
532 
533 } // namespace __lsan
534