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
36using namespace __lsan;
37
38extern "C" {
39int pthread_attr_init(void *attr);
40int pthread_attr_destroy(void *attr);
41int pthread_attr_getdetachstate(void *attr, int *v);
42int pthread_key_create(unsigned *key, void (*destructor)(void* v));
43int pthread_setspecific(unsigned key, const void *v);
44}
45
46///// Malloc/free interceptors. /////
47
48namespace std {
49  struct nothrow_t;
50  enum class align_val_t: size_t;
51}
52
53#if !SANITIZER_MAC
54INTERCEPTOR(void*, malloc, uptr size) {
55  ENSURE_LSAN_INITED;
56  GET_STACK_TRACE_MALLOC;
57  return lsan_malloc(size, stack);
58}
59
60INTERCEPTOR(void, free, void *p) {
61  ENSURE_LSAN_INITED;
62  lsan_free(p);
63}
64
65INTERCEPTOR(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
86INTERCEPTOR(void*, realloc, void *q, uptr size) {
87  ENSURE_LSAN_INITED;
88  GET_STACK_TRACE_MALLOC;
89  return lsan_realloc(q, size, stack);
90}
91
92INTERCEPTOR(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
98INTERCEPTOR(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
104INTERCEPTOR(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
112INTERCEPTOR(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
119INTERCEPTOR(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
133INTERCEPTOR(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
144INTERCEPTOR(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
155struct fake_mallinfo {
156  int x[10];
157};
158
159INTERCEPTOR(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
166INTERCEPTOR(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
176INTERCEPTOR(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
187INTERCEPTOR(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
194INTERCEPTOR(int, mcheck, void (*abortfunc)(int mstatus)) {
195  return 0;
196}
197
198INTERCEPTOR(int, mcheck_pedantic, void (*abortfunc)(int mstatus)) {
199  return 0;
200}
201
202INTERCEPTOR(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
234INTERCEPTOR_ATTRIBUTE
235void *operator new(size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); }
236INTERCEPTOR_ATTRIBUTE
237void *operator new[](size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); }
238INTERCEPTOR_ATTRIBUTE
239void *operator new(size_t size, std::nothrow_t const&)
240{ OPERATOR_NEW_BODY(true /*nothrow*/); }
241INTERCEPTOR_ATTRIBUTE
242void *operator new[](size_t size, std::nothrow_t const&)
243{ OPERATOR_NEW_BODY(true /*nothrow*/); }
244INTERCEPTOR_ATTRIBUTE
245void *operator new(size_t size, std::align_val_t align)
246{ OPERATOR_NEW_BODY_ALIGN(false /*nothrow*/); }
247INTERCEPTOR_ATTRIBUTE
248void *operator new[](size_t size, std::align_val_t align)
249{ OPERATOR_NEW_BODY_ALIGN(false /*nothrow*/); }
250INTERCEPTOR_ATTRIBUTE
251void *operator new(size_t size, std::align_val_t align, std::nothrow_t const&)
252{ OPERATOR_NEW_BODY_ALIGN(true /*nothrow*/); }
253INTERCEPTOR_ATTRIBUTE
254void *operator new[](size_t size, std::align_val_t align, std::nothrow_t const&)
255{ OPERATOR_NEW_BODY_ALIGN(true /*nothrow*/); }
256
257INTERCEPTOR_ATTRIBUTE
258void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
259INTERCEPTOR_ATTRIBUTE
260void operator delete[](void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
261INTERCEPTOR_ATTRIBUTE
262void operator delete(void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY; }
263INTERCEPTOR_ATTRIBUTE
264void operator delete[](void *ptr, std::nothrow_t const &)
265{ OPERATOR_DELETE_BODY; }
266INTERCEPTOR_ATTRIBUTE
267void operator delete(void *ptr, size_t size) NOEXCEPT
268{ OPERATOR_DELETE_BODY; }
269INTERCEPTOR_ATTRIBUTE
270void operator delete[](void *ptr, size_t size) NOEXCEPT
271{ OPERATOR_DELETE_BODY; }
272INTERCEPTOR_ATTRIBUTE
273void operator delete(void *ptr, std::align_val_t) NOEXCEPT
274{ OPERATOR_DELETE_BODY; }
275INTERCEPTOR_ATTRIBUTE
276void operator delete[](void *ptr, std::align_val_t) NOEXCEPT
277{ OPERATOR_DELETE_BODY; }
278INTERCEPTOR_ATTRIBUTE
279void operator delete(void *ptr, std::align_val_t, std::nothrow_t const&)
280{ OPERATOR_DELETE_BODY; }
281INTERCEPTOR_ATTRIBUTE
282void operator delete[](void *ptr, std::align_val_t, std::nothrow_t const&)
283{ OPERATOR_DELETE_BODY; }
284INTERCEPTOR_ATTRIBUTE
285void operator delete(void *ptr, size_t size, std::align_val_t) NOEXCEPT
286{ OPERATOR_DELETE_BODY; }
287INTERCEPTOR_ATTRIBUTE
288void operator delete[](void *ptr, size_t size, std::align_val_t) NOEXCEPT
289{ OPERATOR_DELETE_BODY; }
290
291#else  // SANITIZER_MAC
292
293INTERCEPTOR(void *, _Znwm, size_t size)
294{ OPERATOR_NEW_BODY(false /*nothrow*/); }
295INTERCEPTOR(void *, _Znam, size_t size)
296{ OPERATOR_NEW_BODY(false /*nothrow*/); }
297INTERCEPTOR(void *, _ZnwmRKSt9nothrow_t, size_t size, std::nothrow_t const&)
298{ OPERATOR_NEW_BODY(true /*nothrow*/); }
299INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&)
300{ OPERATOR_NEW_BODY(true /*nothrow*/); }
301
302INTERCEPTOR(void, _ZdlPv, void *ptr)
303{ OPERATOR_DELETE_BODY; }
304INTERCEPTOR(void, _ZdaPv, void *ptr)
305{ OPERATOR_DELETE_BODY; }
306INTERCEPTOR(void, _ZdlPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&)
307{ OPERATOR_DELETE_BODY; }
308INTERCEPTOR(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
317static unsigned g_thread_finalize_key;
318
319static 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
333INTERCEPTOR(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
344INTERCEPTOR(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
355INTERCEPTOR(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
366INTERCEPTOR(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
376extern "C" {
377extern int _pthread_atfork(void (*prepare)(), void (*parent)(),
378                           void (*child)());
379};
380
381INTERCEPTOR(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
394INTERCEPTOR(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
405struct ThreadParam {
406  void *(*callback)(void *arg);
407  void *param;
408  atomic_uintptr_t tid;
409};
410
411extern "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
432INTERCEPTOR(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
470INTERCEPTOR(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
479INTERCEPTOR(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
489namespace __lsan {
490
491void 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