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