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"
21 #include "sanitizer_common/sanitizer_tls_get_addr.h"
23 #include "lsan_allocator.h"
24 #include "lsan_common.h"
25 #include "lsan_thread.h"
27 using namespace __lsan
;
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
);
37 #define ENSURE_LSAN_INITED do { \
38 CHECK(!lsan_init_is_running); \
43 ///// Malloc/free interceptors. /////
45 const bool kAlwaysClearMemory
= true;
51 INTERCEPTOR(void*, malloc
, uptr size
) {
53 GET_STACK_TRACE_MALLOC
;
54 return Allocate(stack
, size
, 1, kAlwaysClearMemory
);
57 INTERCEPTOR(void, free
, void *p
) {
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
);
74 if (CallocShouldReturnNullDueToOverflow(size
, nmemb
)) return nullptr;
76 GET_STACK_TRACE_MALLOC
;
78 return Allocate(stack
, size
, 1, true);
81 INTERCEPTOR(void*, realloc
, void *q
, uptr size
) {
83 GET_STACK_TRACE_MALLOC
;
84 return Reallocate(stack
, q
, size
, 1);
87 INTERCEPTOR(void*, memalign
, uptr alignment
, uptr size
) {
89 GET_STACK_TRACE_MALLOC
;
90 return Allocate(stack
, size
, alignment
, kAlwaysClearMemory
);
93 INTERCEPTOR(void*, aligned_alloc
, uptr alignment
, uptr size
) {
95 GET_STACK_TRACE_MALLOC
;
96 return Allocate(stack
, size
, alignment
, kAlwaysClearMemory
);
99 INTERCEPTOR(int, posix_memalign
, void **memptr
, uptr alignment
, uptr size
) {
101 GET_STACK_TRACE_MALLOC
;
102 *memptr
= Allocate(stack
, size
, alignment
, kAlwaysClearMemory
);
103 // FIXME: Return ENOMEM if user requested more than max alloc size.
107 INTERCEPTOR(void *, __libc_memalign
, uptr alignment
, uptr size
) {
109 GET_STACK_TRACE_MALLOC
;
110 void *res
= Allocate(stack
, size
, alignment
, kAlwaysClearMemory
);
111 DTLS_on_libc_memalign(res
, size
);
115 INTERCEPTOR(void*, valloc
, uptr size
) {
117 GET_STACK_TRACE_MALLOC
;
119 size
= GetPageSizeCached();
120 return Allocate(stack
, size
, GetPageSizeCached(), kAlwaysClearMemory
);
123 INTERCEPTOR(uptr
, malloc_usable_size
, void *ptr
) {
125 return GetMallocUsableSize(ptr
);
128 struct fake_mallinfo
{
132 INTERCEPTOR(struct fake_mallinfo
, mallinfo
, void) {
133 struct fake_mallinfo res
;
134 internal_memset(&res
, 0, sizeof(res
));
138 INTERCEPTOR(int, mallopt
, int cmd
, int value
) {
142 INTERCEPTOR(void*, pvalloc
, uptr size
) {
144 GET_STACK_TRACE_MALLOC
;
145 uptr PageSize
= GetPageSizeCached();
146 size
= RoundUpTo(size
, PageSize
);
148 // pvalloc(0) should allocate one page.
151 return Allocate(stack
, size
, GetPageSizeCached(), kAlwaysClearMemory
);
154 INTERCEPTOR(void, cfree
, void *p
) ALIAS(WRAPPER_NAME(free
));
156 #define OPERATOR_NEW_BODY \
157 ENSURE_LSAN_INITED; \
158 GET_STACK_TRACE_MALLOC; \
159 return Allocate(stack, size, 1, kAlwaysClearMemory);
161 INTERCEPTOR_ATTRIBUTE
162 void *operator new(uptr size
) { OPERATOR_NEW_BODY
; }
163 INTERCEPTOR_ATTRIBUTE
164 void *operator new[](uptr size
) { OPERATOR_NEW_BODY
; }
165 INTERCEPTOR_ATTRIBUTE
166 void *operator new(uptr size
, std::nothrow_t
const&) { OPERATOR_NEW_BODY
; }
167 INTERCEPTOR_ATTRIBUTE
168 void *operator new[](uptr size
, std::nothrow_t
const&) { OPERATOR_NEW_BODY
; }
170 #define OPERATOR_DELETE_BODY \
171 ENSURE_LSAN_INITED; \
174 INTERCEPTOR_ATTRIBUTE
175 void operator delete(void *ptr
) NOEXCEPT
{ OPERATOR_DELETE_BODY
; }
176 INTERCEPTOR_ATTRIBUTE
177 void operator delete[](void *ptr
) NOEXCEPT
{ OPERATOR_DELETE_BODY
; }
178 INTERCEPTOR_ATTRIBUTE
179 void operator delete(void *ptr
, std::nothrow_t
const&) { OPERATOR_DELETE_BODY
; }
180 INTERCEPTOR_ATTRIBUTE
181 void operator delete[](void *ptr
, std::nothrow_t
const &) {
182 OPERATOR_DELETE_BODY
;
185 ///// Thread initialization and finalization. /////
187 static unsigned g_thread_finalize_key
;
189 static void thread_finalize(void *v
) {
192 if (pthread_setspecific(g_thread_finalize_key
, (void*)(iter
- 1))) {
193 Report("LeakSanitizer: failed to set thread key.\n");
202 void *(*callback
)(void *arg
);
204 atomic_uintptr_t tid
;
207 extern "C" void *__lsan_thread_start_func(void *arg
) {
208 ThreadParam
*p
= (ThreadParam
*)arg
;
209 void* (*callback
)(void *arg
) = p
->callback
;
210 void *param
= p
->param
;
211 // Wait until the last iteration to maximize the chance that we are the last
212 // destructor to run.
213 if (pthread_setspecific(g_thread_finalize_key
,
214 (void*)GetPthreadDestructorIterations())) {
215 Report("LeakSanitizer: failed to set thread key.\n");
219 while ((tid
= atomic_load(&p
->tid
, memory_order_acquire
)) == 0)
220 internal_sched_yield();
221 SetCurrentThread(tid
);
222 ThreadStart(tid
, GetTid());
223 atomic_store(&p
->tid
, 0, memory_order_release
);
224 return callback(param
);
227 INTERCEPTOR(int, pthread_create
, void *th
, void *attr
,
228 void *(*callback
)(void *), void *param
) {
230 EnsureMainThreadIDIsCorrect();
231 __sanitizer_pthread_attr_t myattr
;
233 pthread_attr_init(&myattr
);
236 AdjustStackSize(attr
);
238 pthread_attr_getdetachstate(attr
, &detached
);
240 p
.callback
= callback
;
242 atomic_store(&p
.tid
, 0, memory_order_relaxed
);
245 // Ignore all allocations made by pthread_create: thread stack/TLS may be
246 // stored by pthread for future reuse even after thread destruction, and
247 // the linked list it's stored in doesn't even hold valid pointers to the
248 // objects, the latter are calculated by obscure pointer arithmetic.
249 ScopedInterceptorDisabler disabler
;
250 res
= REAL(pthread_create
)(th
, attr
, __lsan_thread_start_func
, &p
);
253 int tid
= ThreadCreate(GetCurrentThread(), *(uptr
*)th
, detached
);
255 atomic_store(&p
.tid
, tid
, memory_order_release
);
256 while (atomic_load(&p
.tid
, memory_order_acquire
) != 0)
257 internal_sched_yield();
260 pthread_attr_destroy(&myattr
);
264 INTERCEPTOR(int, pthread_join
, void *th
, void **ret
) {
266 int tid
= ThreadTid((uptr
)th
);
267 int res
= REAL(pthread_join
)(th
, ret
);
275 void InitializeInterceptors() {
276 INTERCEPT_FUNCTION(malloc
);
277 INTERCEPT_FUNCTION(free
);
278 INTERCEPT_FUNCTION(cfree
);
279 INTERCEPT_FUNCTION(calloc
);
280 INTERCEPT_FUNCTION(realloc
);
281 INTERCEPT_FUNCTION(memalign
);
282 INTERCEPT_FUNCTION(posix_memalign
);
283 INTERCEPT_FUNCTION(__libc_memalign
);
284 INTERCEPT_FUNCTION(valloc
);
285 INTERCEPT_FUNCTION(pvalloc
);
286 INTERCEPT_FUNCTION(malloc_usable_size
);
287 INTERCEPT_FUNCTION(mallinfo
);
288 INTERCEPT_FUNCTION(mallopt
);
289 INTERCEPT_FUNCTION(pthread_create
);
290 INTERCEPT_FUNCTION(pthread_join
);
292 if (pthread_key_create(&g_thread_finalize_key
, &thread_finalize
)) {
293 Report("LeakSanitizer: failed to create thread key.\n");
298 } // namespace __lsan