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