1 //=-- lsan_interceptors.cc ------------------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // This file is a part of LeakSanitizer.
9 // Interceptors for standalone LSan.
11 //===----------------------------------------------------------------------===//
13 #include "interception/interception.h"
14 #include "sanitizer_common/sanitizer_allocator.h"
15 #include "sanitizer_common/sanitizer_atomic.h"
16 #include "sanitizer_common/sanitizer_common.h"
17 #include "sanitizer_common/sanitizer_flags.h"
18 #include "sanitizer_common/sanitizer_internal_defs.h"
19 #include "sanitizer_common/sanitizer_linux.h"
20 #include "sanitizer_common/sanitizer_platform_limits_posix.h"
22 #include "lsan_allocator.h"
23 #include "lsan_thread.h"
25 using namespace __lsan
;
28 int pthread_attr_init(void *attr
);
29 int pthread_attr_destroy(void *attr
);
30 int pthread_attr_getdetachstate(void *attr
, int *v
);
31 int pthread_key_create(unsigned *key
, void (*destructor
)(void* v
));
32 int pthread_setspecific(unsigned key
, const void *v
);
35 #define GET_STACK_TRACE \
38 uptr stack_top = 0, stack_bottom = 0; \
40 bool fast = common_flags()->fast_unwind_on_malloc; \
41 if (fast && (t = CurrentThreadContext())) { \
42 stack_top = t->stack_end(); \
43 stack_bottom = t->stack_begin(); \
45 GetStackTrace(&stack, __sanitizer::common_flags()->malloc_context_size, \
46 StackTrace::GetCurrentPc(), \
47 GET_CURRENT_FRAME(), stack_top, stack_bottom, fast); \
50 ///// Malloc/free interceptors. /////
52 const bool kAlwaysClearMemory
= true;
58 INTERCEPTOR(void*, malloc
, uptr size
) {
61 return Allocate(stack
, size
, 1, kAlwaysClearMemory
);
64 INTERCEPTOR(void, free
, void *p
) {
69 INTERCEPTOR(void*, calloc
, uptr nmemb
, uptr size
) {
70 if (CallocShouldReturnNullDueToOverflow(size
, nmemb
)) return 0;
74 return Allocate(stack
, size
, 1, true);
77 INTERCEPTOR(void*, realloc
, void *q
, uptr size
) {
80 return Reallocate(stack
, q
, size
, 1);
83 INTERCEPTOR(void*, memalign
, uptr alignment
, uptr size
) {
86 return Allocate(stack
, size
, alignment
, kAlwaysClearMemory
);
89 INTERCEPTOR(int, posix_memalign
, void **memptr
, uptr alignment
, uptr size
) {
92 *memptr
= Allocate(stack
, size
, alignment
, kAlwaysClearMemory
);
93 // FIXME: Return ENOMEM if user requested more than max alloc size.
97 INTERCEPTOR(void*, valloc
, uptr size
) {
101 size
= GetPageSizeCached();
102 return Allocate(stack
, size
, GetPageSizeCached(), kAlwaysClearMemory
);
105 INTERCEPTOR(uptr
, malloc_usable_size
, void *ptr
) {
107 return GetMallocUsableSize(ptr
);
110 struct fake_mallinfo
{
114 INTERCEPTOR(struct fake_mallinfo
, mallinfo
, void) {
115 struct fake_mallinfo res
;
116 internal_memset(&res
, 0, sizeof(res
));
120 INTERCEPTOR(int, mallopt
, int cmd
, int value
) {
124 INTERCEPTOR(void*, pvalloc
, uptr size
) {
127 uptr PageSize
= GetPageSizeCached();
128 size
= RoundUpTo(size
, PageSize
);
130 // pvalloc(0) should allocate one page.
133 return Allocate(stack
, size
, GetPageSizeCached(), kAlwaysClearMemory
);
136 INTERCEPTOR(void, cfree
, void *p
) ALIAS("free");
138 #define OPERATOR_NEW_BODY \
141 return Allocate(stack, size, 1, kAlwaysClearMemory);
143 INTERCEPTOR_ATTRIBUTE
144 void *operator new(uptr size
) { OPERATOR_NEW_BODY
; }
145 INTERCEPTOR_ATTRIBUTE
146 void *operator new[](uptr size
) { OPERATOR_NEW_BODY
; }
147 INTERCEPTOR_ATTRIBUTE
148 void *operator new(uptr size
, std::nothrow_t
const&) { OPERATOR_NEW_BODY
; }
149 INTERCEPTOR_ATTRIBUTE
150 void *operator new[](uptr size
, std::nothrow_t
const&) { OPERATOR_NEW_BODY
; }
152 #define OPERATOR_DELETE_BODY \
156 INTERCEPTOR_ATTRIBUTE
157 void operator delete(void *ptr
) { OPERATOR_DELETE_BODY
; }
158 INTERCEPTOR_ATTRIBUTE
159 void operator delete[](void *ptr
) { OPERATOR_DELETE_BODY
; }
160 INTERCEPTOR_ATTRIBUTE
161 void operator delete(void *ptr
, std::nothrow_t
const&) { OPERATOR_DELETE_BODY
; }
162 INTERCEPTOR_ATTRIBUTE
163 void operator delete[](void *ptr
, std::nothrow_t
const &) {
164 OPERATOR_DELETE_BODY
;
167 // We need this to intercept the __libc_memalign calls that are used to
168 // allocate dynamic TLS space in ld-linux.so.
169 INTERCEPTOR(void *, __libc_memalign
, uptr align
, uptr s
) ALIAS("memalign");
171 ///// Thread initialization and finalization. /////
173 static unsigned g_thread_finalize_key
;
175 static void thread_finalize(void *v
) {
178 if (pthread_setspecific(g_thread_finalize_key
, (void*)(iter
- 1))) {
179 Report("LeakSanitizer: failed to set thread key.\n");
188 void *(*callback
)(void *arg
);
190 atomic_uintptr_t tid
;
193 // PTHREAD_DESTRUCTOR_ITERATIONS from glibc.
194 const uptr kPthreadDestructorIterations
= 4;
196 extern "C" void *__lsan_thread_start_func(void *arg
) {
197 ThreadParam
*p
= (ThreadParam
*)arg
;
198 void* (*callback
)(void *arg
) = p
->callback
;
199 void *param
= p
->param
;
200 // Wait until the last iteration to maximize the chance that we are the last
201 // destructor to run.
202 if (pthread_setspecific(g_thread_finalize_key
,
203 (void*)kPthreadDestructorIterations
)) {
204 Report("LeakSanitizer: failed to set thread key.\n");
208 while ((tid
= atomic_load(&p
->tid
, memory_order_acquire
)) == 0)
209 internal_sched_yield();
210 atomic_store(&p
->tid
, 0, memory_order_release
);
211 SetCurrentThread(tid
);
212 ThreadStart(tid
, GetTid());
213 return callback(param
);
216 INTERCEPTOR(int, pthread_create
, void *th
, void *attr
,
217 void *(*callback
)(void *), void *param
) {
219 EnsureMainThreadIDIsCorrect();
220 __sanitizer_pthread_attr_t myattr
;
222 pthread_attr_init(&myattr
);
225 AdjustStackSizeLinux(attr
, 0);
227 pthread_attr_getdetachstate(attr
, &detached
);
229 p
.callback
= callback
;
231 atomic_store(&p
.tid
, 0, memory_order_relaxed
);
232 int res
= REAL(pthread_create
)(th
, attr
, __lsan_thread_start_func
, &p
);
234 int tid
= ThreadCreate(GetCurrentThread(), *(uptr
*)th
, detached
);
236 atomic_store(&p
.tid
, tid
, memory_order_release
);
237 while (atomic_load(&p
.tid
, memory_order_acquire
) != 0)
238 internal_sched_yield();
241 pthread_attr_destroy(&myattr
);
245 INTERCEPTOR(int, pthread_join
, void *th
, void **ret
) {
247 int tid
= ThreadTid((uptr
)th
);
248 int res
= REAL(pthread_join
)(th
, ret
);
256 void InitializeInterceptors() {
257 INTERCEPT_FUNCTION(malloc
);
258 INTERCEPT_FUNCTION(free
);
259 INTERCEPT_FUNCTION(cfree
);
260 INTERCEPT_FUNCTION(calloc
);
261 INTERCEPT_FUNCTION(realloc
);
262 INTERCEPT_FUNCTION(memalign
);
263 INTERCEPT_FUNCTION(posix_memalign
);
264 INTERCEPT_FUNCTION(__libc_memalign
);
265 INTERCEPT_FUNCTION(valloc
);
266 INTERCEPT_FUNCTION(pvalloc
);
267 INTERCEPT_FUNCTION(malloc_usable_size
);
268 INTERCEPT_FUNCTION(mallinfo
);
269 INTERCEPT_FUNCTION(mallopt
);
270 INTERCEPT_FUNCTION(pthread_create
);
271 INTERCEPT_FUNCTION(pthread_join
);
273 if (pthread_key_create(&g_thread_finalize_key
, &thread_finalize
)) {
274 Report("LeakSanitizer: failed to create thread key.\n");
279 } // namespace __lsan