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