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
33using namespace __lsan;
34
35extern "C" {
36int pthread_attr_init(void *attr);
37int pthread_attr_destroy(void *attr);
38int pthread_attr_getdetachstate(void *attr, int *v);
39int pthread_key_create(unsigned *key, void (*destructor)(void* v));
40int pthread_setspecific(unsigned key, const void *v);
41}
42
43///// Malloc/free interceptors. /////
44
45namespace std {
46  struct nothrow_t;
47  enum class align_val_t: size_t;
48}
49
50#if !SANITIZER_MAC
51INTERCEPTOR(void*, malloc, uptr size) {
52  ENSURE_LSAN_INITED;
53  GET_STACK_TRACE_MALLOC;
54  return lsan_malloc(size, stack);
55}
56
57INTERCEPTOR(void, free, void *p) {
58  ENSURE_LSAN_INITED;
59  lsan_free(p);
60}
61
62INTERCEPTOR(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
79INTERCEPTOR(void*, realloc, void *q, uptr size) {
80  ENSURE_LSAN_INITED;
81  GET_STACK_TRACE_MALLOC;
82  return lsan_realloc(q, size, stack);
83}
84
85INTERCEPTOR(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
91INTERCEPTOR(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
99INTERCEPTOR(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
106INTERCEPTOR(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
120INTERCEPTOR(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
131INTERCEPTOR(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
142struct fake_mallinfo {
143  int x[10];
144};
145
146INTERCEPTOR(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
153INTERCEPTOR(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
163INTERCEPTOR(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
174INTERCEPTOR(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
181INTERCEPTOR(int, mcheck, void (*abortfunc)(int mstatus)) {
182  return 0;
183}
184
185INTERCEPTOR(int, mcheck_pedantic, void (*abortfunc)(int mstatus)) {
186  return 0;
187}
188
189INTERCEPTOR(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
221INTERCEPTOR_ATTRIBUTE
222void *operator new(size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); }
223INTERCEPTOR_ATTRIBUTE
224void *operator new[](size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); }
225INTERCEPTOR_ATTRIBUTE
226void *operator new(size_t size, std::nothrow_t const&)
227{ OPERATOR_NEW_BODY(true /*nothrow*/); }
228INTERCEPTOR_ATTRIBUTE
229void *operator new[](size_t size, std::nothrow_t const&)
230{ OPERATOR_NEW_BODY(true /*nothrow*/); }
231INTERCEPTOR_ATTRIBUTE
232void *operator new(size_t size, std::align_val_t align)
233{ OPERATOR_NEW_BODY_ALIGN(false /*nothrow*/); }
234INTERCEPTOR_ATTRIBUTE
235void *operator new[](size_t size, std::align_val_t align)
236{ OPERATOR_NEW_BODY_ALIGN(false /*nothrow*/); }
237INTERCEPTOR_ATTRIBUTE
238void *operator new(size_t size, std::align_val_t align, std::nothrow_t const&)
239{ OPERATOR_NEW_BODY_ALIGN(true /*nothrow*/); }
240INTERCEPTOR_ATTRIBUTE
241void *operator new[](size_t size, std::align_val_t align, std::nothrow_t const&)
242{ OPERATOR_NEW_BODY_ALIGN(true /*nothrow*/); }
243
244INTERCEPTOR_ATTRIBUTE
245void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
246INTERCEPTOR_ATTRIBUTE
247void operator delete[](void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
248INTERCEPTOR_ATTRIBUTE
249void operator delete(void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY; }
250INTERCEPTOR_ATTRIBUTE
251void operator delete[](void *ptr, std::nothrow_t const &)
252{ OPERATOR_DELETE_BODY; }
253INTERCEPTOR_ATTRIBUTE
254void operator delete(void *ptr, size_t size) NOEXCEPT
255{ OPERATOR_DELETE_BODY; }
256INTERCEPTOR_ATTRIBUTE
257void operator delete[](void *ptr, size_t size) NOEXCEPT
258{ OPERATOR_DELETE_BODY; }
259INTERCEPTOR_ATTRIBUTE
260void operator delete(void *ptr, std::align_val_t) NOEXCEPT
261{ OPERATOR_DELETE_BODY; }
262INTERCEPTOR_ATTRIBUTE
263void operator delete[](void *ptr, std::align_val_t) NOEXCEPT
264{ OPERATOR_DELETE_BODY; }
265INTERCEPTOR_ATTRIBUTE
266void operator delete(void *ptr, std::align_val_t, std::nothrow_t const&)
267{ OPERATOR_DELETE_BODY; }
268INTERCEPTOR_ATTRIBUTE
269void operator delete[](void *ptr, std::align_val_t, std::nothrow_t const&)
270{ OPERATOR_DELETE_BODY; }
271INTERCEPTOR_ATTRIBUTE
272void operator delete(void *ptr, size_t size, std::align_val_t) NOEXCEPT
273{ OPERATOR_DELETE_BODY; }
274INTERCEPTOR_ATTRIBUTE
275void operator delete[](void *ptr, size_t size, std::align_val_t) NOEXCEPT
276{ OPERATOR_DELETE_BODY; }
277
278#else  // SANITIZER_MAC
279
280INTERCEPTOR(void *, _Znwm, size_t size)
281{ OPERATOR_NEW_BODY(false /*nothrow*/); }
282INTERCEPTOR(void *, _Znam, size_t size)
283{ OPERATOR_NEW_BODY(false /*nothrow*/); }
284INTERCEPTOR(void *, _ZnwmRKSt9nothrow_t, size_t size, std::nothrow_t const&)
285{ OPERATOR_NEW_BODY(true /*nothrow*/); }
286INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&)
287{ OPERATOR_NEW_BODY(true /*nothrow*/); }
288
289INTERCEPTOR(void, _ZdlPv, void *ptr)
290{ OPERATOR_DELETE_BODY; }
291INTERCEPTOR(void, _ZdaPv, void *ptr)
292{ OPERATOR_DELETE_BODY; }
293INTERCEPTOR(void, _ZdlPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&)
294{ OPERATOR_DELETE_BODY; }
295INTERCEPTOR(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
304static unsigned g_thread_finalize_key;
305
306static 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
320INTERCEPTOR(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
331INTERCEPTOR(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
342INTERCEPTOR(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
352INTERCEPTOR(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
363INTERCEPTOR(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
373extern "C" {
374extern int _pthread_atfork(void (*prepare)(), void (*parent)(),
375                           void (*child)());
376};
377
378INTERCEPTOR(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
389struct ThreadParam {
390  void *(*callback)(void *arg);
391  void *param;
392  atomic_uintptr_t tid;
393};
394
395extern "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
417INTERCEPTOR(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
455INTERCEPTOR(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
464INTERCEPTOR(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
472namespace __lsan {
473
474void 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