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