lsan_interceptors.cc revision 74c88796a4024922144660ed1ade519af5008fe2
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 stack.Unwind(__sanitizer::common_flags()->malloc_context_size, \ 48 StackTrace::GetCurrentPc(), \ 49 GET_CURRENT_FRAME(), stack_top, stack_bottom, fast); \ 50 } 51 52#define ENSURE_LSAN_INITED do { \ 53 CHECK(!lsan_init_is_running); \ 54 if (!lsan_inited) \ 55 __lsan_init(); \ 56} while (0) 57 58///// Malloc/free interceptors. ///// 59 60const bool kAlwaysClearMemory = true; 61 62namespace std { 63 struct nothrow_t; 64} 65 66INTERCEPTOR(void*, malloc, uptr size) { 67 ENSURE_LSAN_INITED; 68 GET_STACK_TRACE; 69 return Allocate(stack, size, 1, kAlwaysClearMemory); 70} 71 72INTERCEPTOR(void, free, void *p) { 73 ENSURE_LSAN_INITED; 74 Deallocate(p); 75} 76 77INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { 78 if (lsan_init_is_running) { 79 // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym. 80 const uptr kCallocPoolSize = 1024; 81 static uptr calloc_memory_for_dlsym[kCallocPoolSize]; 82 static uptr allocated; 83 uptr size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize; 84 void *mem = (void*)&calloc_memory_for_dlsym[allocated]; 85 allocated += size_in_words; 86 CHECK(allocated < kCallocPoolSize); 87 return mem; 88 } 89 if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return 0; 90 ENSURE_LSAN_INITED; 91 GET_STACK_TRACE; 92 size *= nmemb; 93 return Allocate(stack, size, 1, true); 94} 95 96INTERCEPTOR(void*, realloc, void *q, uptr size) { 97 ENSURE_LSAN_INITED; 98 GET_STACK_TRACE; 99 return Reallocate(stack, q, size, 1); 100} 101 102INTERCEPTOR(void*, memalign, uptr alignment, uptr size) { 103 ENSURE_LSAN_INITED; 104 GET_STACK_TRACE; 105 return Allocate(stack, size, alignment, kAlwaysClearMemory); 106} 107 108INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) { 109 ENSURE_LSAN_INITED; 110 GET_STACK_TRACE; 111 *memptr = Allocate(stack, size, alignment, kAlwaysClearMemory); 112 // FIXME: Return ENOMEM if user requested more than max alloc size. 113 return 0; 114} 115 116INTERCEPTOR(void*, valloc, uptr size) { 117 ENSURE_LSAN_INITED; 118 GET_STACK_TRACE; 119 if (size == 0) 120 size = GetPageSizeCached(); 121 return Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory); 122} 123 124INTERCEPTOR(uptr, malloc_usable_size, void *ptr) { 125 ENSURE_LSAN_INITED; 126 return GetMallocUsableSize(ptr); 127} 128 129struct fake_mallinfo { 130 int x[10]; 131}; 132 133INTERCEPTOR(struct fake_mallinfo, mallinfo, void) { 134 struct fake_mallinfo res; 135 internal_memset(&res, 0, sizeof(res)); 136 return res; 137} 138 139INTERCEPTOR(int, mallopt, int cmd, int value) { 140 return -1; 141} 142 143INTERCEPTOR(void*, pvalloc, uptr size) { 144 ENSURE_LSAN_INITED; 145 GET_STACK_TRACE; 146 uptr PageSize = GetPageSizeCached(); 147 size = RoundUpTo(size, PageSize); 148 if (size == 0) { 149 // pvalloc(0) should allocate one page. 150 size = PageSize; 151 } 152 return Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory); 153} 154 155INTERCEPTOR(void, cfree, void *p) ALIAS("free"); 156 157#define OPERATOR_NEW_BODY \ 158 ENSURE_LSAN_INITED; \ 159 GET_STACK_TRACE; \ 160 return Allocate(stack, size, 1, kAlwaysClearMemory); 161 162INTERCEPTOR_ATTRIBUTE 163void *operator new(uptr size) { OPERATOR_NEW_BODY; } 164INTERCEPTOR_ATTRIBUTE 165void *operator new[](uptr size) { OPERATOR_NEW_BODY; } 166INTERCEPTOR_ATTRIBUTE 167void *operator new(uptr size, std::nothrow_t const&) { OPERATOR_NEW_BODY; } 168INTERCEPTOR_ATTRIBUTE 169void *operator new[](uptr size, std::nothrow_t const&) { OPERATOR_NEW_BODY; } 170 171#define OPERATOR_DELETE_BODY \ 172 ENSURE_LSAN_INITED; \ 173 Deallocate(ptr); 174 175INTERCEPTOR_ATTRIBUTE 176void operator delete(void *ptr) { OPERATOR_DELETE_BODY; } 177INTERCEPTOR_ATTRIBUTE 178void operator delete[](void *ptr) { OPERATOR_DELETE_BODY; } 179INTERCEPTOR_ATTRIBUTE 180void operator delete(void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY; } 181INTERCEPTOR_ATTRIBUTE 182void operator delete[](void *ptr, std::nothrow_t const &) { 183 OPERATOR_DELETE_BODY; 184} 185 186// We need this to intercept the __libc_memalign calls that are used to 187// allocate dynamic TLS space in ld-linux.so. 188INTERCEPTOR(void *, __libc_memalign, uptr align, uptr s) ALIAS("memalign"); 189 190///// Thread initialization and finalization. ///// 191 192static unsigned g_thread_finalize_key; 193 194static void thread_finalize(void *v) { 195 uptr iter = (uptr)v; 196 if (iter > 1) { 197 if (pthread_setspecific(g_thread_finalize_key, (void*)(iter - 1))) { 198 Report("LeakSanitizer: failed to set thread key.\n"); 199 Die(); 200 } 201 return; 202 } 203 ThreadFinish(); 204} 205 206struct ThreadParam { 207 void *(*callback)(void *arg); 208 void *param; 209 atomic_uintptr_t tid; 210}; 211 212extern "C" void *__lsan_thread_start_func(void *arg) { 213 ThreadParam *p = (ThreadParam*)arg; 214 void* (*callback)(void *arg) = p->callback; 215 void *param = p->param; 216 // Wait until the last iteration to maximize the chance that we are the last 217 // destructor to run. 218 if (pthread_setspecific(g_thread_finalize_key, 219 (void*)kPthreadDestructorIterations)) { 220 Report("LeakSanitizer: failed to set thread key.\n"); 221 Die(); 222 } 223 int tid = 0; 224 while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0) 225 internal_sched_yield(); 226 atomic_store(&p->tid, 0, memory_order_release); 227 SetCurrentThread(tid); 228 ThreadStart(tid, GetTid()); 229 return callback(param); 230} 231 232INTERCEPTOR(int, pthread_create, void *th, void *attr, 233 void *(*callback)(void *), void *param) { 234 ENSURE_LSAN_INITED; 235 EnsureMainThreadIDIsCorrect(); 236 __sanitizer_pthread_attr_t myattr; 237 if (attr == 0) { 238 pthread_attr_init(&myattr); 239 attr = &myattr; 240 } 241 AdjustStackSizeLinux(attr); 242 int detached = 0; 243 pthread_attr_getdetachstate(attr, &detached); 244 ThreadParam p; 245 p.callback = callback; 246 p.param = param; 247 atomic_store(&p.tid, 0, memory_order_relaxed); 248 int res = REAL(pthread_create)(th, attr, __lsan_thread_start_func, &p); 249 if (res == 0) { 250 int tid = ThreadCreate(GetCurrentThread(), *(uptr *)th, detached); 251 CHECK_NE(tid, 0); 252 atomic_store(&p.tid, tid, memory_order_release); 253 while (atomic_load(&p.tid, memory_order_acquire) != 0) 254 internal_sched_yield(); 255 } 256 if (attr == &myattr) 257 pthread_attr_destroy(&myattr); 258 return res; 259} 260 261INTERCEPTOR(int, pthread_join, void *th, void **ret) { 262 ENSURE_LSAN_INITED; 263 int tid = ThreadTid((uptr)th); 264 int res = REAL(pthread_join)(th, ret); 265 if (res == 0) 266 ThreadJoin(tid); 267 return res; 268} 269 270namespace __lsan { 271 272void InitializeInterceptors() { 273 INTERCEPT_FUNCTION(malloc); 274 INTERCEPT_FUNCTION(free); 275 INTERCEPT_FUNCTION(cfree); 276 INTERCEPT_FUNCTION(calloc); 277 INTERCEPT_FUNCTION(realloc); 278 INTERCEPT_FUNCTION(memalign); 279 INTERCEPT_FUNCTION(posix_memalign); 280 INTERCEPT_FUNCTION(__libc_memalign); 281 INTERCEPT_FUNCTION(valloc); 282 INTERCEPT_FUNCTION(pvalloc); 283 INTERCEPT_FUNCTION(malloc_usable_size); 284 INTERCEPT_FUNCTION(mallinfo); 285 INTERCEPT_FUNCTION(mallopt); 286 INTERCEPT_FUNCTION(pthread_create); 287 INTERCEPT_FUNCTION(pthread_join); 288 289 if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) { 290 Report("LeakSanitizer: failed to create thread key.\n"); 291 Die(); 292 } 293} 294 295} // namespace __lsan 296