blob: d5089f9f7b362131d2c25ca98e9f664f54f7abb3 [file] [log] [blame]
Alexey Samsonove5f58952012-06-04 13:50:10 +00001//===-- asan_malloc_linux.cc ----------------------------------------------===//
Kostya Serebryany1e172b42011-11-30 01:07:02 +00002//
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 AddressSanitizer, an address sanity checker.
11//
12// Linux-specific malloc interception.
13// We simply define functions like malloc, free, realloc, etc.
14// They will replace the corresponding libc functions automagically.
15//===----------------------------------------------------------------------===//
Evgeniy Stepanov24e13722013-03-19 14:33:38 +000016
17#include "sanitizer_common/sanitizer_platform.h"
Stephen Hines2d1fdb22014-05-28 23:58:16 -070018#if SANITIZER_FREEBSD || SANITIZER_LINUX
Kostya Serebryany1e172b42011-11-30 01:07:02 +000019
Stephen Hines2d1fdb22014-05-28 23:58:16 -070020#include "sanitizer_common/sanitizer_tls_get_addr.h"
Kostya Serebryany1e172b42011-11-30 01:07:02 +000021#include "asan_allocator.h"
22#include "asan_interceptors.h"
23#include "asan_internal.h"
24#include "asan_stack.h"
25
Kostya Serebryany1e172b42011-11-30 01:07:02 +000026// ---------------------- Replacement functions ---------------- {{{1
27using namespace __asan; // NOLINT
28
Pirama Arumuga Nainar799172d2016-03-03 15:50:30 -080029static const uptr kCallocPoolSize = 1024;
30static uptr calloc_memory_for_dlsym[kCallocPoolSize];
31
32static bool IsInCallocPool(const void *ptr) {
33 sptr off = (sptr)ptr - (sptr)calloc_memory_for_dlsym;
34 return 0 <= off && off < (sptr)kCallocPoolSize;
35}
36
Alexey Samsonovf2598fc2012-02-02 10:39:40 +000037INTERCEPTOR(void, free, void *ptr) {
Kostya Serebryanya30c8f92012-12-13 09:34:23 +000038 GET_STACK_TRACE_FREE;
Pirama Arumuga Nainar799172d2016-03-03 15:50:30 -080039 if (UNLIKELY(IsInCallocPool(ptr)))
40 return;
Kostya Serebryanyfe6d9162012-12-21 08:53:59 +000041 asan_free(ptr, &stack, FROM_MALLOC);
Kostya Serebryany1e172b42011-11-30 01:07:02 +000042}
43
Alexey Samsonovf2598fc2012-02-02 10:39:40 +000044INTERCEPTOR(void, cfree, void *ptr) {
Kostya Serebryanya30c8f92012-12-13 09:34:23 +000045 GET_STACK_TRACE_FREE;
Pirama Arumuga Nainar799172d2016-03-03 15:50:30 -080046 if (UNLIKELY(IsInCallocPool(ptr)))
47 return;
Kostya Serebryanyfe6d9162012-12-21 08:53:59 +000048 asan_free(ptr, &stack, FROM_MALLOC);
Kostya Serebryany1e172b42011-11-30 01:07:02 +000049}
50
Kostya Serebryanye7539bf2012-06-25 09:58:29 +000051INTERCEPTOR(void*, malloc, uptr size) {
Kostya Serebryanya30c8f92012-12-13 09:34:23 +000052 GET_STACK_TRACE_MALLOC;
Kostya Serebryany1e172b42011-11-30 01:07:02 +000053 return asan_malloc(size, &stack);
54}
55
Kostya Serebryanye7539bf2012-06-25 09:58:29 +000056INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
Stephen Hines2d1fdb22014-05-28 23:58:16 -070057 if (UNLIKELY(!asan_inited)) {
Alexey Samsonov09672ca2012-02-08 13:45:31 +000058 // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
Kostya Serebryanye7539bf2012-06-25 09:58:29 +000059 static uptr allocated;
60 uptr size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize;
Kostya Serebryany1e172b42011-11-30 01:07:02 +000061 void *mem = (void*)&calloc_memory_for_dlsym[allocated];
62 allocated += size_in_words;
63 CHECK(allocated < kCallocPoolSize);
64 return mem;
65 }
Kostya Serebryanya30c8f92012-12-13 09:34:23 +000066 GET_STACK_TRACE_MALLOC;
Kostya Serebryany1e172b42011-11-30 01:07:02 +000067 return asan_calloc(nmemb, size, &stack);
68}
69
Kostya Serebryanye7539bf2012-06-25 09:58:29 +000070INTERCEPTOR(void*, realloc, void *ptr, uptr size) {
Kostya Serebryanya30c8f92012-12-13 09:34:23 +000071 GET_STACK_TRACE_MALLOC;
Pirama Arumuga Nainar799172d2016-03-03 15:50:30 -080072 if (UNLIKELY(IsInCallocPool(ptr))) {
73 uptr offset = (uptr)ptr - (uptr)calloc_memory_for_dlsym;
74 uptr copy_size = Min(size, kCallocPoolSize - offset);
75 void *new_ptr = asan_malloc(size, &stack);
76 internal_memcpy(new_ptr, ptr, copy_size);
77 return new_ptr;
78 }
Kostya Serebryany1e172b42011-11-30 01:07:02 +000079 return asan_realloc(ptr, size, &stack);
80}
81
Kostya Serebryanye7539bf2012-06-25 09:58:29 +000082INTERCEPTOR(void*, memalign, uptr boundary, uptr size) {
Kostya Serebryanya30c8f92012-12-13 09:34:23 +000083 GET_STACK_TRACE_MALLOC;
Kostya Serebryanyfe6d9162012-12-21 08:53:59 +000084 return asan_memalign(boundary, size, &stack, FROM_MALLOC);
Kostya Serebryany1e172b42011-11-30 01:07:02 +000085}
86
Stephen Hines6a211c52014-07-21 00:49:56 -070087INTERCEPTOR(void*, aligned_alloc, uptr boundary, uptr size) {
88 GET_STACK_TRACE_MALLOC;
89 return asan_memalign(boundary, size, &stack, FROM_MALLOC);
90}
91
Stephen Hines2d1fdb22014-05-28 23:58:16 -070092INTERCEPTOR(void*, __libc_memalign, uptr boundary, uptr size) {
93 GET_STACK_TRACE_MALLOC;
94 void *res = asan_memalign(boundary, size, &stack, FROM_MALLOC);
95 DTLS_on_libc_memalign(res, size * boundary);
96 return res;
97}
Kostya Serebryany1e172b42011-11-30 01:07:02 +000098
Kostya Serebryanye7539bf2012-06-25 09:58:29 +000099INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
Alexey Samsonov1b17f5b2013-11-13 14:46:58 +0000100 GET_CURRENT_PC_BP_SP;
101 (void)sp;
102 return asan_malloc_usable_size(ptr, pc, bp);
Alexey Samsonov4fd95f12012-01-17 06:39:10 +0000103}
104
Kostya Serebryanye7539bf2012-06-25 09:58:29 +0000105// We avoid including malloc.h for portability reasons.
106// man mallinfo says the fields are "long", but the implementation uses int.
107// It doesn't matter much -- we just need to make sure that the libc's mallinfo
108// is not called.
109struct fake_mallinfo {
110 int x[10];
111};
112
113INTERCEPTOR(struct fake_mallinfo, mallinfo, void) {
114 struct fake_mallinfo res;
Alexey Samsonov09672ca2012-02-08 13:45:31 +0000115 REAL(memset)(&res, 0, sizeof(res));
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000116 return res;
117}
118
Alexey Samsonovf2598fc2012-02-02 10:39:40 +0000119INTERCEPTOR(int, mallopt, int cmd, int value) {
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000120 return -1;
121}
122
Kostya Serebryanye7539bf2012-06-25 09:58:29 +0000123INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
Kostya Serebryanya30c8f92012-12-13 09:34:23 +0000124 GET_STACK_TRACE_MALLOC;
Evgeniy Stepanov739eb792012-03-21 11:32:46 +0000125 // Printf("posix_memalign: %zx %zu\n", alignment, size);
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000126 return asan_posix_memalign(memptr, alignment, size, &stack);
127}
128
Kostya Serebryanye7539bf2012-06-25 09:58:29 +0000129INTERCEPTOR(void*, valloc, uptr size) {
Kostya Serebryanya30c8f92012-12-13 09:34:23 +0000130 GET_STACK_TRACE_MALLOC;
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000131 return asan_valloc(size, &stack);
132}
133
Kostya Serebryanye7539bf2012-06-25 09:58:29 +0000134INTERCEPTOR(void*, pvalloc, uptr size) {
Kostya Serebryanya30c8f92012-12-13 09:34:23 +0000135 GET_STACK_TRACE_MALLOC;
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000136 return asan_pvalloc(size, &stack);
137}
Kostya Serebryanyd6567c52011-12-01 21:40:52 +0000138
Kostya Serebryany73bad812012-12-20 11:54:21 +0000139INTERCEPTOR(void, malloc_stats, void) {
Kostya Serebryany709a33e2012-12-26 12:20:35 +0000140 __asan_print_accumulated_stats();
Kostya Serebryany73bad812012-12-20 11:54:21 +0000141}
142
Stephen Hines6d186232014-11-26 17:56:19 -0800143#if SANITIZER_ANDROID
144// Format of __libc_malloc_dispatch has changed in Android L.
145// While we are moving towards a solution that does not depend on bionic
146// internals, here is something to support both K* and L releases.
147struct MallocDebugK {
148 void *(*malloc)(uptr bytes);
149 void (*free)(void *mem);
150 void *(*calloc)(uptr n_elements, uptr elem_size);
151 void *(*realloc)(void *oldMem, uptr bytes);
152 void *(*memalign)(uptr alignment, uptr bytes);
153 uptr (*malloc_usable_size)(void *mem);
154};
155
156struct MallocDebugL {
157 void *(*calloc)(uptr n_elements, uptr elem_size);
158 void (*free)(void *mem);
159 fake_mallinfo (*mallinfo)(void);
160 void *(*malloc)(uptr bytes);
161 uptr (*malloc_usable_size)(void *mem);
162 void *(*memalign)(uptr alignment, uptr bytes);
163 int (*posix_memalign)(void **memptr, uptr alignment, uptr size);
164 void* (*pvalloc)(uptr size);
165 void *(*realloc)(void *oldMem, uptr bytes);
166 void* (*valloc)(uptr size);
167};
168
169ALIGNED(32) const MallocDebugK asan_malloc_dispatch_k = {
170 WRAP(malloc), WRAP(free), WRAP(calloc),
171 WRAP(realloc), WRAP(memalign), WRAP(malloc_usable_size)};
172
173ALIGNED(32) const MallocDebugL asan_malloc_dispatch_l = {
174 WRAP(calloc), WRAP(free), WRAP(mallinfo),
175 WRAP(malloc), WRAP(malloc_usable_size), WRAP(memalign),
176 WRAP(posix_memalign), WRAP(pvalloc), WRAP(realloc),
177 WRAP(valloc)};
178
179namespace __asan {
180void ReplaceSystemMalloc() {
181 void **__libc_malloc_dispatch_p =
182 (void **)AsanDlSymNext("__libc_malloc_dispatch");
183 if (__libc_malloc_dispatch_p) {
184 // Decide on K vs L dispatch format by the presence of
185 // __libc_malloc_default_dispatch export in libc.
186 void *default_dispatch_p = AsanDlSymNext("__libc_malloc_default_dispatch");
187 if (default_dispatch_p)
188 *__libc_malloc_dispatch_p = (void *)&asan_malloc_dispatch_k;
189 else
190 *__libc_malloc_dispatch_p = (void *)&asan_malloc_dispatch_l;
191 }
192}
193} // namespace __asan
194
195#else // SANITIZER_ANDROID
196
197namespace __asan {
198void ReplaceSystemMalloc() {
199}
200} // namespace __asan
201#endif // SANITIZER_ANDROID
202
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700203#endif // SANITIZER_FREEBSD || SANITIZER_LINUX