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