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 #else 119 #define LSAN_MAYBE_INTERCEPT_MEMALIGN 120 #endif // SANITIZER_INTERCEPT_MEMALIGN 121 122 #if SANITIZER_INTERCEPT___LIBC_MEMALIGN 123 INTERCEPTOR(void *, __libc_memalign, uptr alignment, uptr size) { 124 ENSURE_LSAN_INITED; 125 GET_STACK_TRACE_MALLOC; 126 void *res = lsan_memalign(alignment, size, stack); 127 DTLS_on_libc_memalign(res, size); 128 return res; 129 } 130 #define LSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN INTERCEPT_FUNCTION(__libc_memalign) 131 #else 132 #define LSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN 133 #endif // SANITIZER_INTERCEPT___LIBC_MEMALIGN 134 135 #if SANITIZER_INTERCEPT_ALIGNED_ALLOC 136 INTERCEPTOR(void*, aligned_alloc, uptr alignment, uptr size) { 137 ENSURE_LSAN_INITED; 138 GET_STACK_TRACE_MALLOC; 139 return lsan_aligned_alloc(alignment, size, stack); 140 } 141 #define LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC INTERCEPT_FUNCTION(aligned_alloc) 142 #else 143 #define LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC 144 #endif 145 146 #if SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE 147 INTERCEPTOR(uptr, malloc_usable_size, void *ptr) { 148 ENSURE_LSAN_INITED; 149 return GetMallocUsableSize(ptr); 150 } 151 #define LSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE \ 152 INTERCEPT_FUNCTION(malloc_usable_size) 153 #else 154 #define LSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE 155 #endif 156 157 #if SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO 158 struct fake_mallinfo { 159 int x[10]; 160 }; 161 162 INTERCEPTOR(struct fake_mallinfo, mallinfo, void) { 163 struct fake_mallinfo res; 164 internal_memset(&res, 0, sizeof(res)); 165 return res; 166 } 167 #define LSAN_MAYBE_INTERCEPT_MALLINFO INTERCEPT_FUNCTION(mallinfo) 168 169 INTERCEPTOR(int, mallopt, int cmd, int value) { 170 return 0; 171 } 172 #define LSAN_MAYBE_INTERCEPT_MALLOPT INTERCEPT_FUNCTION(mallopt) 173 #else 174 #define LSAN_MAYBE_INTERCEPT_MALLINFO 175 #define LSAN_MAYBE_INTERCEPT_MALLOPT 176 #endif // SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO 177 178 #if SANITIZER_INTERCEPT_PVALLOC 179 INTERCEPTOR(void*, pvalloc, uptr size) { 180 ENSURE_LSAN_INITED; 181 GET_STACK_TRACE_MALLOC; 182 return lsan_pvalloc(size, stack); 183 } 184 #define LSAN_MAYBE_INTERCEPT_PVALLOC INTERCEPT_FUNCTION(pvalloc) 185 #else 186 #define LSAN_MAYBE_INTERCEPT_PVALLOC 187 #endif // SANITIZER_INTERCEPT_PVALLOC 188 189 #if SANITIZER_INTERCEPT_CFREE 190 INTERCEPTOR(void, cfree, void *p) ALIAS(WRAPPER_NAME(free)); 191 #define LSAN_MAYBE_INTERCEPT_CFREE INTERCEPT_FUNCTION(cfree) 192 #else 193 #define LSAN_MAYBE_INTERCEPT_CFREE 194 #endif // SANITIZER_INTERCEPT_CFREE 195 196 #if SANITIZER_INTERCEPT_MCHECK_MPROBE 197 INTERCEPTOR(int, mcheck, void (*abortfunc)(int mstatus)) { 198 return 0; 199 } 200 201 INTERCEPTOR(int, mcheck_pedantic, void (*abortfunc)(int mstatus)) { 202 return 0; 203 } 204 205 INTERCEPTOR(int, mprobe, void *ptr) { 206 return 0; 207 } 208 #endif // SANITIZER_INTERCEPT_MCHECK_MPROBE 209 210 211 // TODO(alekseys): throw std::bad_alloc instead of dying on OOM. 212 #define OPERATOR_NEW_BODY(nothrow)\ 213 ENSURE_LSAN_INITED;\ 214 GET_STACK_TRACE_MALLOC;\ 215 void *res = lsan_malloc(size, stack);\ 216 if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\ 217 return res; 218 #define OPERATOR_NEW_BODY_ALIGN(nothrow)\ 219 ENSURE_LSAN_INITED;\ 220 GET_STACK_TRACE_MALLOC;\ 221 void *res = lsan_memalign((uptr)align, size, stack);\ 222 if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\ 223 return res; 224 225 #define OPERATOR_DELETE_BODY\ 226 ENSURE_LSAN_INITED;\ 227 lsan_free(ptr); 228 229 // On OS X it's not enough to just provide our own 'operator new' and 230 // 'operator delete' implementations, because they're going to be in the runtime 231 // dylib, and the main executable will depend on both the runtime dylib and 232 // libstdc++, each of has its implementation of new and delete. 233 // To make sure that C++ allocation/deallocation operators are overridden on 234 // OS X we need to intercept them using their mangled names. 235 #if !SANITIZER_MAC 236 237 INTERCEPTOR_ATTRIBUTE 238 void *operator new(size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); } 239 INTERCEPTOR_ATTRIBUTE 240 void *operator new[](size_t size) { OPERATOR_NEW_BODY(false /*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::nothrow_t const&) 246 { OPERATOR_NEW_BODY(true /*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) 252 { OPERATOR_NEW_BODY_ALIGN(false /*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 INTERCEPTOR_ATTRIBUTE 257 void *operator new[](size_t size, std::align_val_t align, std::nothrow_t const&) 258 { OPERATOR_NEW_BODY_ALIGN(true /*nothrow*/); } 259 260 INTERCEPTOR_ATTRIBUTE 261 void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; } 262 INTERCEPTOR_ATTRIBUTE 263 void operator delete[](void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; } 264 INTERCEPTOR_ATTRIBUTE 265 void operator delete(void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY; } 266 INTERCEPTOR_ATTRIBUTE 267 void operator delete[](void *ptr, std::nothrow_t const &) 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, size_t size) 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) NOEXCEPT 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, std::align_val_t, std::nothrow_t const&) 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 INTERCEPTOR_ATTRIBUTE 291 void operator delete[](void *ptr, size_t size, std::align_val_t) NOEXCEPT 292 { OPERATOR_DELETE_BODY; } 293 294 #else // SANITIZER_MAC 295 296 INTERCEPTOR(void *, _Znwm, size_t size) 297 { OPERATOR_NEW_BODY(false /*nothrow*/); } 298 INTERCEPTOR(void *, _Znam, size_t size) 299 { OPERATOR_NEW_BODY(false /*nothrow*/); } 300 INTERCEPTOR(void *, _ZnwmRKSt9nothrow_t, size_t size, std::nothrow_t const&) 301 { OPERATOR_NEW_BODY(true /*nothrow*/); } 302 INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) 303 { OPERATOR_NEW_BODY(true /*nothrow*/); } 304 305 INTERCEPTOR(void, _ZdlPv, void *ptr) 306 { OPERATOR_DELETE_BODY; } 307 INTERCEPTOR(void, _ZdaPv, void *ptr) 308 { OPERATOR_DELETE_BODY; } 309 INTERCEPTOR(void, _ZdlPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&) 310 { OPERATOR_DELETE_BODY; } 311 INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&) 312 { OPERATOR_DELETE_BODY; } 313 314 #endif // !SANITIZER_MAC 315 316 317 ///// Thread initialization and finalization. ///// 318 319 #if !SANITIZER_NETBSD && !SANITIZER_FREEBSD && !SANITIZER_FUCHSIA 320 static unsigned g_thread_finalize_key; 321 322 static void thread_finalize(void *v) { 323 uptr iter = (uptr)v; 324 if (iter > 1) { 325 if (pthread_setspecific(g_thread_finalize_key, (void*)(iter - 1))) { 326 Report("LeakSanitizer: failed to set thread key.\n"); 327 Die(); 328 } 329 return; 330 } 331 ThreadFinish(); 332 } 333 #endif 334 335 #if SANITIZER_NETBSD 336 INTERCEPTOR(void, _lwp_exit) { 337 ENSURE_LSAN_INITED; 338 ThreadFinish(); 339 REAL(_lwp_exit)(); 340 } 341 #define LSAN_MAYBE_INTERCEPT__LWP_EXIT INTERCEPT_FUNCTION(_lwp_exit) 342 #else 343 #define LSAN_MAYBE_INTERCEPT__LWP_EXIT 344 #endif 345 346 #if SANITIZER_INTERCEPT_THR_EXIT 347 INTERCEPTOR(void, thr_exit, tid_t *state) { 348 ENSURE_LSAN_INITED; 349 ThreadFinish(); 350 REAL(thr_exit)(state); 351 } 352 #define LSAN_MAYBE_INTERCEPT_THR_EXIT INTERCEPT_FUNCTION(thr_exit) 353 #else 354 #define LSAN_MAYBE_INTERCEPT_THR_EXIT 355 #endif 356 357 #if SANITIZER_INTERCEPT___CXA_ATEXIT 358 INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg, 359 void *dso_handle) { 360 __lsan::ScopedInterceptorDisabler disabler; 361 return REAL(__cxa_atexit)(func, arg, dso_handle); 362 } 363 #define LSAN_MAYBE_INTERCEPT___CXA_ATEXIT INTERCEPT_FUNCTION(__cxa_atexit) 364 #else 365 #define LSAN_MAYBE_INTERCEPT___CXA_ATEXIT 366 #endif 367 368 #if SANITIZER_INTERCEPT_ATEXIT 369 INTERCEPTOR(int, atexit, void (*f)()) { 370 __lsan::ScopedInterceptorDisabler disabler; 371 return REAL(__cxa_atexit)((void (*)(void *a))f, 0, 0); 372 } 373 #define LSAN_MAYBE_INTERCEPT_ATEXIT INTERCEPT_FUNCTION(atexit) 374 #else 375 #define LSAN_MAYBE_INTERCEPT_ATEXIT 376 #endif 377 378 #if SANITIZER_INTERCEPT_PTHREAD_ATFORK 379 extern "C" { 380 extern int _pthread_atfork(void (*prepare)(), void (*parent)(), 381 void (*child)()); 382 }; 383 384 INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(), 385 void (*child)()) { 386 __lsan::ScopedInterceptorDisabler disabler; 387 // REAL(pthread_atfork) cannot be called due to symbol indirections at least 388 // on NetBSD 389 return _pthread_atfork(prepare, parent, child); 390 } 391 #define LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK INTERCEPT_FUNCTION(pthread_atfork) 392 #else 393 #define LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK 394 #endif 395 396 #if SANITIZER_INTERCEPT_STRERROR 397 INTERCEPTOR(char *, strerror, int errnum) { 398 __lsan::ScopedInterceptorDisabler disabler; 399 return REAL(strerror)(errnum); 400 } 401 #define LSAN_MAYBE_INTERCEPT_STRERROR INTERCEPT_FUNCTION(strerror) 402 #else 403 #define LSAN_MAYBE_INTERCEPT_STRERROR 404 #endif 405 406 #if SANITIZER_POSIX 407 408 struct ThreadParam { 409 void *(*callback)(void *arg); 410 void *param; 411 atomic_uintptr_t tid; 412 }; 413 414 extern "C" void *__lsan_thread_start_func(void *arg) { 415 ThreadParam *p = (ThreadParam*)arg; 416 void* (*callback)(void *arg) = p->callback; 417 void *param = p->param; 418 // Wait until the last iteration to maximize the chance that we are the last 419 // destructor to run. 420 #if !SANITIZER_NETBSD && !SANITIZER_FREEBSD 421 if (pthread_setspecific(g_thread_finalize_key, 422 (void*)GetPthreadDestructorIterations())) { 423 Report("LeakSanitizer: failed to set thread key.\n"); 424 Die(); 425 } 426 #endif 427 int tid = 0; 428 while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0) 429 internal_sched_yield(); 430 ThreadStart(tid, GetTid()); 431 atomic_store(&p->tid, 0, memory_order_release); 432 return callback(param); 433 } 434 435 INTERCEPTOR(int, pthread_create, void *th, void *attr, 436 void *(*callback)(void *), void *param) { 437 ENSURE_LSAN_INITED; 438 EnsureMainThreadIDIsCorrect(); 439 __sanitizer_pthread_attr_t myattr; 440 if (!attr) { 441 pthread_attr_init(&myattr); 442 attr = &myattr; 443 } 444 AdjustStackSize(attr); 445 int detached = 0; 446 pthread_attr_getdetachstate(attr, &detached); 447 ThreadParam p; 448 p.callback = callback; 449 p.param = param; 450 atomic_store(&p.tid, 0, memory_order_relaxed); 451 int res; 452 { 453 // Ignore all allocations made by pthread_create: thread stack/TLS may be 454 // stored by pthread for future reuse even after thread destruction, and 455 // the linked list it's stored in doesn't even hold valid pointers to the 456 // objects, the latter are calculated by obscure pointer arithmetic. 457 ScopedInterceptorDisabler disabler; 458 res = REAL(pthread_create)(th, attr, __lsan_thread_start_func, &p); 459 } 460 if (res == 0) { 461 int tid = ThreadCreate(GetCurrentThread(), *(uptr *)th, 462 IsStateDetached(detached)); 463 CHECK_NE(tid, 0); 464 atomic_store(&p.tid, tid, memory_order_release); 465 while (atomic_load(&p.tid, memory_order_acquire) != 0) 466 internal_sched_yield(); 467 } 468 if (attr == &myattr) 469 pthread_attr_destroy(&myattr); 470 return res; 471 } 472 473 INTERCEPTOR(int, pthread_join, void *th, void **ret) { 474 ENSURE_LSAN_INITED; 475 int tid = ThreadTid((uptr)th); 476 int res = REAL(pthread_join)(th, ret); 477 if (res == 0) 478 ThreadJoin(tid); 479 return res; 480 } 481 482 INTERCEPTOR(int, pthread_detach, void *th) { 483 ENSURE_LSAN_INITED; 484 int tid = ThreadTid((uptr)th); 485 int res = REAL(pthread_detach)(th); 486 if (res == 0) 487 ThreadDetach(tid); 488 return res; 489 } 490 491 INTERCEPTOR(void, _exit, int status) { 492 if (status == 0 && HasReportedLeaks()) status = common_flags()->exitcode; 493 REAL(_exit)(status); 494 } 495 496 #define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name) 497 #include "sanitizer_common/sanitizer_signal_interceptors.inc" 498 499 #endif // SANITIZER_POSIX 500 501 namespace __lsan { 502 503 void InitializeInterceptors() { 504 // Fuchsia doesn't use interceptors that require any setup. 505 #if !SANITIZER_FUCHSIA 506 InitializeSignalInterceptors(); 507 508 INTERCEPT_FUNCTION(malloc); 509 INTERCEPT_FUNCTION(free); 510 LSAN_MAYBE_INTERCEPT_CFREE; 511 INTERCEPT_FUNCTION(calloc); 512 INTERCEPT_FUNCTION(realloc); 513 LSAN_MAYBE_INTERCEPT_MEMALIGN; 514 LSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN; 515 LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC; 516 INTERCEPT_FUNCTION(posix_memalign); 517 INTERCEPT_FUNCTION(valloc); 518 LSAN_MAYBE_INTERCEPT_PVALLOC; 519 LSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE; 520 LSAN_MAYBE_INTERCEPT_MALLINFO; 521 LSAN_MAYBE_INTERCEPT_MALLOPT; 522 INTERCEPT_FUNCTION(pthread_create); 523 INTERCEPT_FUNCTION(pthread_detach); 524 INTERCEPT_FUNCTION(pthread_join); 525 INTERCEPT_FUNCTION(_exit); 526 527 LSAN_MAYBE_INTERCEPT__LWP_EXIT; 528 LSAN_MAYBE_INTERCEPT_THR_EXIT; 529 530 LSAN_MAYBE_INTERCEPT___CXA_ATEXIT; 531 LSAN_MAYBE_INTERCEPT_ATEXIT; 532 LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK; 533 534 LSAN_MAYBE_INTERCEPT_STRERROR; 535 536 #if !SANITIZER_NETBSD && !SANITIZER_FREEBSD 537 if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) { 538 Report("LeakSanitizer: failed to create thread key.\n"); 539 Die(); 540 } 541 #endif 542 543 #endif // !SANITIZER_FUCHSIA 544 } 545 546 } // namespace __lsan 547