PR middle-end/78245 - missing -Wformat-length on an overflow of a dynamically allocat...
[official-gcc.git] / libsanitizer / lsan / lsan_interceptors.cc
blob160ed5979c4f2cdac1a46f0a37e15033f57e0c19
1 //=-- lsan_interceptors.cc ------------------------------------------------===//
2 //
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
5 //
6 //===----------------------------------------------------------------------===//
7 //
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"
22 #include "lsan.h"
23 #include "lsan_allocator.h"
24 #include "lsan_common.h"
25 #include "lsan_thread.h"
27 using namespace __lsan;
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);
37 #define ENSURE_LSAN_INITED do { \
38 CHECK(!lsan_init_is_running); \
39 if (!lsan_inited) \
40 __lsan_init(); \
41 } while (0)
43 ///// Malloc/free interceptors. /////
45 const bool kAlwaysClearMemory = true;
47 namespace std {
48 struct nothrow_t;
51 INTERCEPTOR(void*, malloc, uptr size) {
52 ENSURE_LSAN_INITED;
53 GET_STACK_TRACE_MALLOC;
54 return Allocate(stack, size, 1, kAlwaysClearMemory);
57 INTERCEPTOR(void, free, void *p) {
58 ENSURE_LSAN_INITED;
59 Deallocate(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);
72 return mem;
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);
81 INTERCEPTOR(void*, realloc, void *q, uptr size) {
82 ENSURE_LSAN_INITED;
83 GET_STACK_TRACE_MALLOC;
84 return Reallocate(stack, q, size, 1);
87 INTERCEPTOR(void*, memalign, uptr alignment, uptr size) {
88 ENSURE_LSAN_INITED;
89 GET_STACK_TRACE_MALLOC;
90 return Allocate(stack, size, alignment, kAlwaysClearMemory);
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);
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;
107 INTERCEPTOR(void *, __libc_memalign, uptr alignment, uptr size) {
108 ENSURE_LSAN_INITED;
109 GET_STACK_TRACE_MALLOC;
110 void *res = Allocate(stack, size, alignment, kAlwaysClearMemory);
111 DTLS_on_libc_memalign(res, size);
112 return res;
115 INTERCEPTOR(void*, valloc, uptr size) {
116 ENSURE_LSAN_INITED;
117 GET_STACK_TRACE_MALLOC;
118 if (size == 0)
119 size = GetPageSizeCached();
120 return Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory);
123 INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
124 ENSURE_LSAN_INITED;
125 return GetMallocUsableSize(ptr);
128 struct fake_mallinfo {
129 int x[10];
132 INTERCEPTOR(struct fake_mallinfo, mallinfo, void) {
133 struct fake_mallinfo res;
134 internal_memset(&res, 0, sizeof(res));
135 return res;
138 INTERCEPTOR(int, mallopt, int cmd, int value) {
139 return -1;
142 INTERCEPTOR(void*, pvalloc, uptr size) {
143 ENSURE_LSAN_INITED;
144 GET_STACK_TRACE_MALLOC;
145 uptr PageSize = GetPageSizeCached();
146 size = RoundUpTo(size, PageSize);
147 if (size == 0) {
148 // pvalloc(0) should allocate one page.
149 size = PageSize;
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; \
172 Deallocate(ptr);
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) {
190 uptr iter = (uptr)v;
191 if (iter > 1) {
192 if (pthread_setspecific(g_thread_finalize_key, (void*)(iter - 1))) {
193 Report("LeakSanitizer: failed to set thread key.\n");
194 Die();
196 return;
198 ThreadFinish();
201 struct ThreadParam {
202 void *(*callback)(void *arg);
203 void *param;
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");
216 Die();
218 int tid = 0;
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) {
229 ENSURE_LSAN_INITED;
230 EnsureMainThreadIDIsCorrect();
231 __sanitizer_pthread_attr_t myattr;
232 if (!attr) {
233 pthread_attr_init(&myattr);
234 attr = &myattr;
236 AdjustStackSize(attr);
237 int detached = 0;
238 pthread_attr_getdetachstate(attr, &detached);
239 ThreadParam p;
240 p.callback = callback;
241 p.param = param;
242 atomic_store(&p.tid, 0, memory_order_relaxed);
243 int res;
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);
252 if (res == 0) {
253 int tid = ThreadCreate(GetCurrentThread(), *(uptr *)th, detached);
254 CHECK_NE(tid, 0);
255 atomic_store(&p.tid, tid, memory_order_release);
256 while (atomic_load(&p.tid, memory_order_acquire) != 0)
257 internal_sched_yield();
259 if (attr == &myattr)
260 pthread_attr_destroy(&myattr);
261 return res;
264 INTERCEPTOR(int, pthread_join, void *th, void **ret) {
265 ENSURE_LSAN_INITED;
266 int tid = ThreadTid((uptr)th);
267 int res = REAL(pthread_join)(th, ret);
268 if (res == 0)
269 ThreadJoin(tid);
270 return res;
273 namespace __lsan {
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");
294 Die();
298 } // namespace __lsan