Home | History | Annotate | Download | only in lsan
      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_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_limits_posix.h"
     23 #include "sanitizer_common/sanitizer_tls_get_addr.h"
     24 #include "lsan.h"
     25 #include "lsan_allocator.h"
     26 #include "lsan_common.h"
     27 #include "lsan_thread.h"
     28 
     29 using namespace __lsan;
     30 
     31 extern "C" {
     32 int pthread_attr_init(void *attr);
     33 int pthread_attr_destroy(void *attr);
     34 int pthread_attr_getdetachstate(void *attr, int *v);
     35 int pthread_key_create(unsigned *key, void (*destructor)(void* v));
     36 int pthread_setspecific(unsigned key, const void *v);
     37 }
     38 
     39 #define ENSURE_LSAN_INITED do {   \
     40   CHECK(!lsan_init_is_running);   \
     41   if (!lsan_inited)               \
     42     __lsan_init();                \
     43 } while (0)
     44 
     45 ///// Malloc/free interceptors. /////
     46 
     47 const bool kAlwaysClearMemory = true;
     48 
     49 namespace std {
     50   struct nothrow_t;
     51 }
     52 
     53 INTERCEPTOR(void*, malloc, uptr size) {
     54   ENSURE_LSAN_INITED;
     55   GET_STACK_TRACE_MALLOC;
     56   return Allocate(stack, size, 1, kAlwaysClearMemory);
     57 }
     58 
     59 INTERCEPTOR(void, free, void *p) {
     60   ENSURE_LSAN_INITED;
     61   Deallocate(p);
     62 }
     63 
     64 INTERCEPTOR(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   if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return nullptr;
     77   ENSURE_LSAN_INITED;
     78   GET_STACK_TRACE_MALLOC;
     79   size *= nmemb;
     80   return Allocate(stack, size, 1, true);
     81 }
     82 
     83 INTERCEPTOR(void*, realloc, void *q, uptr size) {
     84   ENSURE_LSAN_INITED;
     85   GET_STACK_TRACE_MALLOC;
     86   return Reallocate(stack, q, size, 1);
     87 }
     88 
     89 INTERCEPTOR(void*, memalign, uptr alignment, uptr size) {
     90   ENSURE_LSAN_INITED;
     91   GET_STACK_TRACE_MALLOC;
     92   return Allocate(stack, size, alignment, kAlwaysClearMemory);
     93 }
     94 
     95 INTERCEPTOR(void*, aligned_alloc, uptr alignment, uptr size) {
     96   ENSURE_LSAN_INITED;
     97   GET_STACK_TRACE_MALLOC;
     98   return Allocate(stack, size, alignment, kAlwaysClearMemory);
     99 }
    100 
    101 INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
    102   ENSURE_LSAN_INITED;
    103   GET_STACK_TRACE_MALLOC;
    104   *memptr = Allocate(stack, size, alignment, kAlwaysClearMemory);
    105   // FIXME: Return ENOMEM if user requested more than max alloc size.
    106   return 0;
    107 }
    108 
    109 INTERCEPTOR(void *, __libc_memalign, uptr alignment, uptr size) {
    110   ENSURE_LSAN_INITED;
    111   GET_STACK_TRACE_MALLOC;
    112   void *res = Allocate(stack, size, alignment, kAlwaysClearMemory);
    113   DTLS_on_libc_memalign(res, size);
    114   return res;
    115 }
    116 
    117 INTERCEPTOR(void*, valloc, uptr size) {
    118   ENSURE_LSAN_INITED;
    119   GET_STACK_TRACE_MALLOC;
    120   if (size == 0)
    121     size = GetPageSizeCached();
    122   return Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory);
    123 }
    124 
    125 INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
    126   ENSURE_LSAN_INITED;
    127   return GetMallocUsableSize(ptr);
    128 }
    129 
    130 struct fake_mallinfo {
    131   int x[10];
    132 };
    133 
    134 INTERCEPTOR(struct fake_mallinfo, mallinfo, void) {
    135   struct fake_mallinfo res;
    136   internal_memset(&res, 0, sizeof(res));
    137   return res;
    138 }
    139 
    140 INTERCEPTOR(int, mallopt, int cmd, int value) {
    141   return -1;
    142 }
    143 
    144 INTERCEPTOR(void*, pvalloc, uptr size) {
    145   ENSURE_LSAN_INITED;
    146   GET_STACK_TRACE_MALLOC;
    147   uptr PageSize = GetPageSizeCached();
    148   size = RoundUpTo(size, PageSize);
    149   if (size == 0) {
    150     // pvalloc(0) should allocate one page.
    151     size = PageSize;
    152   }
    153   return Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory);
    154 }
    155 
    156 INTERCEPTOR(void, cfree, void *p) ALIAS(WRAPPER_NAME(free));
    157 
    158 #define OPERATOR_NEW_BODY                              \
    159   ENSURE_LSAN_INITED;                                  \
    160   GET_STACK_TRACE_MALLOC;                              \
    161   return Allocate(stack, size, 1, kAlwaysClearMemory);
    162 
    163 INTERCEPTOR_ATTRIBUTE
    164 void *operator new(uptr size) { OPERATOR_NEW_BODY; }
    165 INTERCEPTOR_ATTRIBUTE
    166 void *operator new[](uptr size) { OPERATOR_NEW_BODY; }
    167 INTERCEPTOR_ATTRIBUTE
    168 void *operator new(uptr size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
    169 INTERCEPTOR_ATTRIBUTE
    170 void *operator new[](uptr size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
    171 
    172 #define OPERATOR_DELETE_BODY \
    173   ENSURE_LSAN_INITED;        \
    174   Deallocate(ptr);
    175 
    176 INTERCEPTOR_ATTRIBUTE
    177 void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
    178 INTERCEPTOR_ATTRIBUTE
    179 void operator delete[](void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
    180 INTERCEPTOR_ATTRIBUTE
    181 void operator delete(void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY; }
    182 INTERCEPTOR_ATTRIBUTE
    183 void operator delete[](void *ptr, std::nothrow_t const &) {
    184   OPERATOR_DELETE_BODY;
    185 }
    186 
    187 ///// Thread initialization and finalization. /////
    188 
    189 static unsigned g_thread_finalize_key;
    190 
    191 static void thread_finalize(void *v) {
    192   uptr iter = (uptr)v;
    193   if (iter > 1) {
    194     if (pthread_setspecific(g_thread_finalize_key, (void*)(iter - 1))) {
    195       Report("LeakSanitizer: failed to set thread key.\n");
    196       Die();
    197     }
    198     return;
    199   }
    200   ThreadFinish();
    201 }
    202 
    203 struct ThreadParam {
    204   void *(*callback)(void *arg);
    205   void *param;
    206   atomic_uintptr_t tid;
    207 };
    208 
    209 extern "C" void *__lsan_thread_start_func(void *arg) {
    210   ThreadParam *p = (ThreadParam*)arg;
    211   void* (*callback)(void *arg) = p->callback;
    212   void *param = p->param;
    213   // Wait until the last iteration to maximize the chance that we are the last
    214   // destructor to run.
    215   if (pthread_setspecific(g_thread_finalize_key,
    216                           (void*)GetPthreadDestructorIterations())) {
    217     Report("LeakSanitizer: failed to set thread key.\n");
    218     Die();
    219   }
    220   int tid = 0;
    221   while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0)
    222     internal_sched_yield();
    223   SetCurrentThread(tid);
    224   ThreadStart(tid, GetTid());
    225   atomic_store(&p->tid, 0, memory_order_release);
    226   return callback(param);
    227 }
    228 
    229 INTERCEPTOR(int, pthread_create, void *th, void *attr,
    230             void *(*callback)(void *), void *param) {
    231   ENSURE_LSAN_INITED;
    232   EnsureMainThreadIDIsCorrect();
    233   __sanitizer_pthread_attr_t myattr;
    234   if (!attr) {
    235     pthread_attr_init(&myattr);
    236     attr = &myattr;
    237   }
    238   AdjustStackSize(attr);
    239   int detached = 0;
    240   pthread_attr_getdetachstate(attr, &detached);
    241   ThreadParam p;
    242   p.callback = callback;
    243   p.param = param;
    244   atomic_store(&p.tid, 0, memory_order_relaxed);
    245   int res;
    246   {
    247     // Ignore all allocations made by pthread_create: thread stack/TLS may be
    248     // stored by pthread for future reuse even after thread destruction, and
    249     // the linked list it's stored in doesn't even hold valid pointers to the
    250     // objects, the latter are calculated by obscure pointer arithmetic.
    251     ScopedInterceptorDisabler disabler;
    252     res = REAL(pthread_create)(th, attr, __lsan_thread_start_func, &p);
    253   }
    254   if (res == 0) {
    255     int tid = ThreadCreate(GetCurrentThread(), *(uptr *)th, detached);
    256     CHECK_NE(tid, 0);
    257     atomic_store(&p.tid, tid, memory_order_release);
    258     while (atomic_load(&p.tid, memory_order_acquire) != 0)
    259       internal_sched_yield();
    260   }
    261   if (attr == &myattr)
    262     pthread_attr_destroy(&myattr);
    263   return res;
    264 }
    265 
    266 INTERCEPTOR(int, pthread_join, void *th, void **ret) {
    267   ENSURE_LSAN_INITED;
    268   int tid = ThreadTid((uptr)th);
    269   int res = REAL(pthread_join)(th, ret);
    270   if (res == 0)
    271     ThreadJoin(tid);
    272   return res;
    273 }
    274 
    275 namespace __lsan {
    276 
    277 void InitializeInterceptors() {
    278   INTERCEPT_FUNCTION(malloc);
    279   INTERCEPT_FUNCTION(free);
    280   INTERCEPT_FUNCTION(cfree);
    281   INTERCEPT_FUNCTION(calloc);
    282   INTERCEPT_FUNCTION(realloc);
    283   INTERCEPT_FUNCTION(memalign);
    284   INTERCEPT_FUNCTION(posix_memalign);
    285   INTERCEPT_FUNCTION(__libc_memalign);
    286   INTERCEPT_FUNCTION(valloc);
    287   INTERCEPT_FUNCTION(pvalloc);
    288   INTERCEPT_FUNCTION(malloc_usable_size);
    289   INTERCEPT_FUNCTION(mallinfo);
    290   INTERCEPT_FUNCTION(mallopt);
    291   INTERCEPT_FUNCTION(pthread_create);
    292   INTERCEPT_FUNCTION(pthread_join);
    293 
    294   if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) {
    295     Report("LeakSanitizer: failed to create thread key.\n");
    296     Die();
    297   }
    298 }
    299 
    300 } // namespace __lsan
    301