lsan_interceptors.cc revision fc1a61203fec6797060744c5c6754b0ae924f5b2
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 "lsan.h" 24#include "lsan_allocator.h" 25#include "lsan_thread.h" 26 27using namespace __lsan; 28 29extern "C" { 30int pthread_attr_init(void *attr); 31int pthread_attr_destroy(void *attr); 32int pthread_attr_getdetachstate(void *attr, int *v); 33int pthread_key_create(unsigned *key, void (*destructor)(void* v)); 34int pthread_setspecific(unsigned key, const void *v); 35} 36 37#define GET_STACK_TRACE \ 38 StackTrace stack; \ 39 { \ 40 uptr stack_top = 0, stack_bottom = 0; \ 41 ThreadContext *t; \ 42 bool fast = common_flags()->fast_unwind_on_malloc; \ 43 if (fast && (t = CurrentThreadContext())) { \ 44 stack_top = t->stack_end(); \ 45 stack_bottom = t->stack_begin(); \ 46 } \ 47 GetStackTrace(&stack, __sanitizer::common_flags()->malloc_context_size, \ 48 StackTrace::GetCurrentPc(), \ 49 GET_CURRENT_FRAME(), stack_top, stack_bottom, fast); \ 50 } 51 52///// Malloc/free interceptors. ///// 53 54namespace std { 55 struct nothrow_t; 56} 57 58INTERCEPTOR(void*, malloc, uptr size) { 59 Init(); 60 GET_STACK_TRACE; 61 return Allocate(stack, size, 1, false); 62} 63 64INTERCEPTOR(void, free, void *p) { 65 Init(); 66 Deallocate(p); 67} 68 69INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { 70 if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return 0; 71 Init(); 72 GET_STACK_TRACE; 73 size *= nmemb; 74 return Allocate(stack, size, 1, true); 75} 76 77INTERCEPTOR(void*, realloc, void *q, uptr size) { 78 Init(); 79 GET_STACK_TRACE; 80 return Reallocate(stack, q, size, 1); 81} 82 83INTERCEPTOR(void*, memalign, uptr alignment, uptr size) { 84 Init(); 85 GET_STACK_TRACE; 86 return Allocate(stack, size, alignment, false); 87} 88 89INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) { 90 Init(); 91 GET_STACK_TRACE; 92 *memptr = Allocate(stack, size, alignment, false); 93 // FIXME: Return ENOMEM if user requested more than max alloc size. 94 return 0; 95} 96 97INTERCEPTOR(void*, valloc, uptr size) { 98 Init(); 99 GET_STACK_TRACE; 100 if (size == 0) 101 size = GetPageSizeCached(); 102 return Allocate(stack, size, GetPageSizeCached(), false); 103} 104 105INTERCEPTOR(uptr, malloc_usable_size, void *ptr) { 106 Init(); 107 return GetMallocUsableSize(ptr); 108} 109 110struct fake_mallinfo { 111 int x[10]; 112}; 113 114INTERCEPTOR(struct fake_mallinfo, mallinfo, void) { 115 struct fake_mallinfo res; 116 internal_memset(&res, 0, sizeof(res)); 117 return res; 118} 119 120INTERCEPTOR(int, mallopt, int cmd, int value) { 121 return -1; 122} 123 124void *operator new(uptr size) ALIAS("malloc") SANITIZER_INTERFACE_ATTRIBUTE; 125void *operator new[](uptr size) ALIAS("malloc") SANITIZER_INTERFACE_ATTRIBUTE; 126void *operator new(uptr size, std::nothrow_t const&) ALIAS("malloc") 127 SANITIZER_INTERFACE_ATTRIBUTE; 128void *operator new[](uptr size, std::nothrow_t const&) ALIAS("malloc") 129 SANITIZER_INTERFACE_ATTRIBUTE; 130void operator delete(void *ptr) ALIAS("free") SANITIZER_INTERFACE_ATTRIBUTE; 131void operator delete[](void *ptr) ALIAS("free") SANITIZER_INTERFACE_ATTRIBUTE; 132void operator delete(void *ptr, std::nothrow_t const&) ALIAS("free") 133 SANITIZER_INTERFACE_ATTRIBUTE; 134void operator delete[](void *ptr, std::nothrow_t const&) ALIAS("free") 135 SANITIZER_INTERFACE_ATTRIBUTE; 136 137extern "C" { 138void cfree(void *p) ALIAS("free") SANITIZER_INTERFACE_ATTRIBUTE; 139void *pvalloc(uptr size) ALIAS("valloc") 140 SANITIZER_INTERFACE_ATTRIBUTE; 141// We need this to intercept the __libc_memalign calls that are used to 142// allocate dynamic TLS space in ld-linux.so. 143void *__libc_memalign(uptr alignment, uptr size) 144 ALIAS("memalign") SANITIZER_INTERFACE_ATTRIBUTE; 145} 146 147///// Thread initialization and finalization. ///// 148 149static unsigned g_thread_finalize_key; 150 151static void thread_finalize(void *v) { 152 uptr iter = (uptr)v; 153 if (iter > 1) { 154 if (pthread_setspecific(g_thread_finalize_key, (void*)(iter - 1))) { 155 Report("LeakSanitizer: failed to set thread key.\n"); 156 Die(); 157 } 158 return; 159 } 160 ThreadFinish(); 161} 162 163struct ThreadParam { 164 void *(*callback)(void *arg); 165 void *param; 166 atomic_uintptr_t tid; 167}; 168 169// PTHREAD_DESTRUCTOR_ITERATIONS from glibc. 170const uptr kPthreadDestructorIterations = 4; 171 172extern "C" void *__lsan_thread_start_func(void *arg) { 173 ThreadParam *p = (ThreadParam*)arg; 174 void* (*callback)(void *arg) = p->callback; 175 void *param = p->param; 176 // Wait until the last iteration to maximize the chance that we are the last 177 // destructor to run. 178 if (pthread_setspecific(g_thread_finalize_key, 179 (void*)kPthreadDestructorIterations)) { 180 Report("LeakSanitizer: failed to set thread key.\n"); 181 Die(); 182 } 183 int tid = 0; 184 while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0) 185 internal_sched_yield(); 186 atomic_store(&p->tid, 0, memory_order_release); 187 SetCurrentThread(tid); 188 ThreadStart(tid, GetTid()); 189 return callback(param); 190} 191 192INTERCEPTOR(int, pthread_create, void *th, void *attr, 193 void *(*callback)(void *), void *param) { 194 Init(); 195 __sanitizer_pthread_attr_t myattr; 196 if (attr == 0) { 197 pthread_attr_init(&myattr); 198 attr = &myattr; 199 } 200 AdjustStackSizeLinux(attr, 0); 201 int detached = 0; 202 pthread_attr_getdetachstate(attr, &detached); 203 ThreadParam p; 204 p.callback = callback; 205 p.param = param; 206 atomic_store(&p.tid, 0, memory_order_relaxed); 207 int res = REAL(pthread_create)(th, attr, __lsan_thread_start_func, &p); 208 if (res == 0) { 209 int tid = ThreadCreate(GetCurrentThread(), *(uptr *)th, detached); 210 CHECK_NE(tid, 0); 211 atomic_store(&p.tid, tid, memory_order_release); 212 while (atomic_load(&p.tid, memory_order_acquire) != 0) 213 internal_sched_yield(); 214 } 215 if (attr == &myattr) 216 pthread_attr_destroy(&myattr); 217 return res; 218} 219 220INTERCEPTOR(int, pthread_join, void *th, void **ret) { 221 Init(); 222 int tid = ThreadTid((uptr)th); 223 int res = REAL(pthread_join)(th, ret); 224 if (res == 0) 225 ThreadJoin(tid); 226 return res; 227} 228 229namespace __lsan { 230 231void InitializeInterceptors() { 232 INTERCEPT_FUNCTION(malloc); 233 INTERCEPT_FUNCTION(free); 234 INTERCEPT_FUNCTION(calloc); 235 INTERCEPT_FUNCTION(realloc); 236 INTERCEPT_FUNCTION(memalign); 237 INTERCEPT_FUNCTION(posix_memalign); 238 INTERCEPT_FUNCTION(memalign); 239 INTERCEPT_FUNCTION(valloc); 240 INTERCEPT_FUNCTION(malloc_usable_size); 241 INTERCEPT_FUNCTION(mallinfo); 242 INTERCEPT_FUNCTION(mallopt); 243 INTERCEPT_FUNCTION(pthread_create); 244 INTERCEPT_FUNCTION(pthread_join); 245 246 if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) { 247 Report("LeakSanitizer: failed to create thread key.\n"); 248 Die(); 249 } 250} 251 252} // namespace __lsan 253