blob: be0d0ddc282e3a470557f340f5586d442f2c984a [file] [log] [blame]
Sergey Matveev7ea7d202013-05-20 11:01:40 +00001//=-- 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
Stephen Hines6d186232014-11-26 17:56:19 -080015#include "interception/interception.h"
Sergey Matveev7ea7d202013-05-20 11:01:40 +000016#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
27using namespace __lsan;
28
29extern "C" {
30int pthread_attr_init(void *attr);
31int pthread_attr_destroy(void *attr);
32int pthread_attr_getdetachstate(void *attr, int *v);
33int pthread_key_create(unsigned *key, void (*destructor)(void* v));
34int pthread_setspecific(unsigned key, const void *v);
35}
36
Sergey Matveev74c88792013-11-25 17:39:36 +000037#define ENSURE_LSAN_INITED do { \
38 CHECK(!lsan_init_is_running); \
39 if (!lsan_inited) \
40 __lsan_init(); \
41} while (0)
42
Sergey Matveev7ea7d202013-05-20 11:01:40 +000043///// Malloc/free interceptors. /////
44
Sergey Matveevd16d7232013-06-25 14:05:52 +000045const bool kAlwaysClearMemory = true;
46
Sergey Matveev7ea7d202013-05-20 11:01:40 +000047namespace std {
48 struct nothrow_t;
49}
50
51INTERCEPTOR(void*, malloc, uptr size) {
Sergey Matveev74c88792013-11-25 17:39:36 +000052 ENSURE_LSAN_INITED;
Stephen Hines6d186232014-11-26 17:56:19 -080053 GET_STACK_TRACE_MALLOC;
Sergey Matveevd16d7232013-06-25 14:05:52 +000054 return Allocate(stack, size, 1, kAlwaysClearMemory);
Sergey Matveev7ea7d202013-05-20 11:01:40 +000055}
56
57INTERCEPTOR(void, free, void *p) {
Sergey Matveev74c88792013-11-25 17:39:36 +000058 ENSURE_LSAN_INITED;
Sergey Matveev7ea7d202013-05-20 11:01:40 +000059 Deallocate(p);
60}
61
62INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
Sergey Matveev74c88792013-11-25 17:39:36 +000063 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 }
Pirama Arumuga Nainar799172d2016-03-03 15:50:30 -080074 if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return nullptr;
Sergey Matveev74c88792013-11-25 17:39:36 +000075 ENSURE_LSAN_INITED;
Stephen Hines6d186232014-11-26 17:56:19 -080076 GET_STACK_TRACE_MALLOC;
Sergey Matveev7ea7d202013-05-20 11:01:40 +000077 size *= nmemb;
78 return Allocate(stack, size, 1, true);
79}
80
81INTERCEPTOR(void*, realloc, void *q, uptr size) {
Sergey Matveev74c88792013-11-25 17:39:36 +000082 ENSURE_LSAN_INITED;
Stephen Hines6d186232014-11-26 17:56:19 -080083 GET_STACK_TRACE_MALLOC;
Sergey Matveev7ea7d202013-05-20 11:01:40 +000084 return Reallocate(stack, q, size, 1);
85}
86
87INTERCEPTOR(void*, memalign, uptr alignment, uptr size) {
Sergey Matveev74c88792013-11-25 17:39:36 +000088 ENSURE_LSAN_INITED;
Stephen Hines6d186232014-11-26 17:56:19 -080089 GET_STACK_TRACE_MALLOC;
Sergey Matveevd16d7232013-06-25 14:05:52 +000090 return Allocate(stack, size, alignment, kAlwaysClearMemory);
Sergey Matveev7ea7d202013-05-20 11:01:40 +000091}
92
Stephen Hines6a211c52014-07-21 00:49:56 -070093INTERCEPTOR(void*, aligned_alloc, uptr alignment, uptr size) {
94 ENSURE_LSAN_INITED;
Stephen Hines6d186232014-11-26 17:56:19 -080095 GET_STACK_TRACE_MALLOC;
Stephen Hines6a211c52014-07-21 00:49:56 -070096 return Allocate(stack, size, alignment, kAlwaysClearMemory);
97}
98
Sergey Matveev7ea7d202013-05-20 11:01:40 +000099INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
Sergey Matveev74c88792013-11-25 17:39:36 +0000100 ENSURE_LSAN_INITED;
Stephen Hines6d186232014-11-26 17:56:19 -0800101 GET_STACK_TRACE_MALLOC;
Sergey Matveevd16d7232013-06-25 14:05:52 +0000102 *memptr = Allocate(stack, size, alignment, kAlwaysClearMemory);
Sergey Matveev7ea7d202013-05-20 11:01:40 +0000103 // FIXME: Return ENOMEM if user requested more than max alloc size.
104 return 0;
105}
106
107INTERCEPTOR(void*, valloc, uptr size) {
Sergey Matveev74c88792013-11-25 17:39:36 +0000108 ENSURE_LSAN_INITED;
Stephen Hines6d186232014-11-26 17:56:19 -0800109 GET_STACK_TRACE_MALLOC;
Sergey Matveev7ea7d202013-05-20 11:01:40 +0000110 if (size == 0)
111 size = GetPageSizeCached();
Sergey Matveevd16d7232013-06-25 14:05:52 +0000112 return Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory);
Sergey Matveev7ea7d202013-05-20 11:01:40 +0000113}
114
115INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
Sergey Matveev74c88792013-11-25 17:39:36 +0000116 ENSURE_LSAN_INITED;
Sergey Matveev7ea7d202013-05-20 11:01:40 +0000117 return GetMallocUsableSize(ptr);
118}
119
120struct fake_mallinfo {
121 int x[10];
122};
123
124INTERCEPTOR(struct fake_mallinfo, mallinfo, void) {
125 struct fake_mallinfo res;
126 internal_memset(&res, 0, sizeof(res));
127 return res;
128}
129
130INTERCEPTOR(int, mallopt, int cmd, int value) {
131 return -1;
132}
133
Sergey Matveevd16d7232013-06-25 14:05:52 +0000134INTERCEPTOR(void*, pvalloc, uptr size) {
Sergey Matveev74c88792013-11-25 17:39:36 +0000135 ENSURE_LSAN_INITED;
Stephen Hines6d186232014-11-26 17:56:19 -0800136 GET_STACK_TRACE_MALLOC;
Sergey Matveevd16d7232013-06-25 14:05:52 +0000137 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}
Sergey Matveev7ea7d202013-05-20 11:01:40 +0000145
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700146INTERCEPTOR(void, cfree, void *p) ALIAS(WRAPPER_NAME(free));
Sergey Matveevd16d7232013-06-25 14:05:52 +0000147
148#define OPERATOR_NEW_BODY \
Sergey Matveev74c88792013-11-25 17:39:36 +0000149 ENSURE_LSAN_INITED; \
Stephen Hines6d186232014-11-26 17:56:19 -0800150 GET_STACK_TRACE_MALLOC; \
Sergey Matveevd16d7232013-06-25 14:05:52 +0000151 return Allocate(stack, size, 1, kAlwaysClearMemory);
152
153INTERCEPTOR_ATTRIBUTE
154void *operator new(uptr size) { OPERATOR_NEW_BODY; }
155INTERCEPTOR_ATTRIBUTE
156void *operator new[](uptr size) { OPERATOR_NEW_BODY; }
157INTERCEPTOR_ATTRIBUTE
158void *operator new(uptr size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
159INTERCEPTOR_ATTRIBUTE
160void *operator new[](uptr size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
161
162#define OPERATOR_DELETE_BODY \
Sergey Matveev74c88792013-11-25 17:39:36 +0000163 ENSURE_LSAN_INITED; \
Sergey Matveevd16d7232013-06-25 14:05:52 +0000164 Deallocate(ptr);
165
166INTERCEPTOR_ATTRIBUTE
Pirama Arumuga Nainar799172d2016-03-03 15:50:30 -0800167void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
Sergey Matveevd16d7232013-06-25 14:05:52 +0000168INTERCEPTOR_ATTRIBUTE
Pirama Arumuga Nainar799172d2016-03-03 15:50:30 -0800169void operator delete[](void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
Sergey Matveevd16d7232013-06-25 14:05:52 +0000170INTERCEPTOR_ATTRIBUTE
171void operator delete(void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY; }
172INTERCEPTOR_ATTRIBUTE
173void operator delete[](void *ptr, std::nothrow_t const &) {
174 OPERATOR_DELETE_BODY;
175}
176
Sergey Matveev7ea7d202013-05-20 11:01:40 +0000177// We need this to intercept the __libc_memalign calls that are used to
178// allocate dynamic TLS space in ld-linux.so.
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700179INTERCEPTOR(void *, __libc_memalign, uptr align, uptr s)
180 ALIAS(WRAPPER_NAME(memalign));
Sergey Matveev7ea7d202013-05-20 11:01:40 +0000181
182///// Thread initialization and finalization. /////
183
184static unsigned g_thread_finalize_key;
185
186static 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
198struct ThreadParam {
199 void *(*callback)(void *arg);
200 void *param;
201 atomic_uintptr_t tid;
202};
203
Sergey Matveev7ea7d202013-05-20 11:01:40 +0000204extern "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,
Pirama Arumuga Nainar799172d2016-03-03 15:50:30 -0800211 (void*)GetPthreadDestructorIterations())) {
Sergey Matveev7ea7d202013-05-20 11:01:40 +0000212 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();
Sergey Matveev7ea7d202013-05-20 11:01:40 +0000218 SetCurrentThread(tid);
219 ThreadStart(tid, GetTid());
Stephen Hines86277eb2015-03-23 12:06:32 -0700220 atomic_store(&p->tid, 0, memory_order_release);
Sergey Matveev7ea7d202013-05-20 11:01:40 +0000221 return callback(param);
222}
223
Sergey Matveevfc1a6122013-05-23 10:24:44 +0000224INTERCEPTOR(int, pthread_create, void *th, void *attr,
225 void *(*callback)(void *), void *param) {
Sergey Matveev74c88792013-11-25 17:39:36 +0000226 ENSURE_LSAN_INITED;
Sergey Matveevc6ac98d2013-07-08 12:57:24 +0000227 EnsureMainThreadIDIsCorrect();
Sergey Matveev7ea7d202013-05-20 11:01:40 +0000228 __sanitizer_pthread_attr_t myattr;
Pirama Arumuga Nainar799172d2016-03-03 15:50:30 -0800229 if (!attr) {
Sergey Matveev7ea7d202013-05-20 11:01:40 +0000230 pthread_attr_init(&myattr);
231 attr = &myattr;
232 }
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700233 AdjustStackSize(attr);
Sergey Matveev7ea7d202013-05-20 11:01:40 +0000234 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
253INTERCEPTOR(int, pthread_join, void *th, void **ret) {
Sergey Matveev74c88792013-11-25 17:39:36 +0000254 ENSURE_LSAN_INITED;
Sergey Matveev7ea7d202013-05-20 11:01:40 +0000255 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
262namespace __lsan {
263
264void InitializeInterceptors() {
265 INTERCEPT_FUNCTION(malloc);
266 INTERCEPT_FUNCTION(free);
Sergey Matveevd16d7232013-06-25 14:05:52 +0000267 INTERCEPT_FUNCTION(cfree);
Sergey Matveev7ea7d202013-05-20 11:01:40 +0000268 INTERCEPT_FUNCTION(calloc);
269 INTERCEPT_FUNCTION(realloc);
270 INTERCEPT_FUNCTION(memalign);
271 INTERCEPT_FUNCTION(posix_memalign);
Sergey Matveevd16d7232013-06-25 14:05:52 +0000272 INTERCEPT_FUNCTION(__libc_memalign);
Sergey Matveev7ea7d202013-05-20 11:01:40 +0000273 INTERCEPT_FUNCTION(valloc);
Sergey Matveevd16d7232013-06-25 14:05:52 +0000274 INTERCEPT_FUNCTION(pvalloc);
Sergey Matveev7ea7d202013-05-20 11:01:40 +0000275 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
Pirama Arumuga Nainar799172d2016-03-03 15:50:30 -0800287} // namespace __lsan