blob: ec8023ff2644c6c4bfa379de7053c113e789084d [file] [log] [blame]
njn3e884182003-04-15 13:03:23 +00001
2/*--------------------------------------------------------------------*/
3/*--- Replacements for malloc() et al, which run on the simulated ---*/
4/*--- CPU. vg_replace_malloc.c ---*/
5/*--------------------------------------------------------------------*/
6
7/*
8 This file is part of Valgrind, an extensible x86 protected-mode
9 emulator for monitoring program execution on x86-Unixes.
10
nethercotebb1c9912004-01-04 16:43:23 +000011 Copyright (C) 2000-2004 Julian Seward
njn3e884182003-04-15 13:03:23 +000012 jseward@acm.org
13
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
29 The GNU General Public License is contained in the file COPYING.
30*/
31
32/* ---------------------------------------------------------------------
rjwalshe4e779d2004-04-16 23:02:29 +000033 All the code in this file runs on the SIMULATED CPU. It is intended
34 for various reasons as drop-in replacements for malloc() and friends.
35 These functions have global scope, but are not intended to be called
36 directly. See the comments in coregrind/vg_intercept.c.base for the
37 gory details.
njn3e884182003-04-15 13:03:23 +000038
rjwalshe4e779d2004-04-16 23:02:29 +000039 This file can be linked into the injected so file for any tool that
40 wishes to know about calls to malloc(). It should define functions
41 SK_(malloc) et al that will be called.
njn3e884182003-04-15 13:03:23 +000042 ------------------------------------------------------------------ */
43
njn72718642003-07-24 08:45:32 +000044#include "valgrind.h" /* for VALGRIND_NON_SIMD_CALL[12] */
rjwalsh7109a8c2004-09-02 00:31:02 +000045#include "core.h"
njn3e884182003-04-15 13:03:23 +000046
rjwalshe4e779d2004-04-16 23:02:29 +000047#define LIBALIAS(ret, name, args) \
48 ret VG_INTERCEPT(soname:libstdc++*, __libc_##name) args \
49 __attribute__((alias(VG_INTERCEPT_ALIAS(soname:libc.so.6, ##name)), \
50 visibility("protected"))); \
51 ret VG_INTERCEPT(soname:libc.so.6, __libc_##name) args \
52 __attribute__((alias(VG_INTERCEPT_ALIAS(soname:libc.so.6, ##name)), \
53 visibility("protected"))); \
54 ret VG_INTERCEPT(soname:libstdc++*, __##name) args \
55 __attribute__((alias(VG_INTERCEPT_ALIAS(soname:libc.so.6, ##name)), \
56 visibility("protected"))); \
57 ret VG_INTERCEPT(soname:libc.so.6, __##name) args \
58 __attribute__((alias(VG_INTERCEPT_ALIAS(soname:libc.so.6, ##name)), \
59 visibility("protected"))); \
60 ret VG_INTERCEPT(soname:libstdc++*, ##name) args \
61 __attribute__((alias(VG_INTERCEPT_ALIAS(soname:libc.so.6, ##name)), \
62 visibility("protected"))); \
63 ret VG_INTERCEPT(soname:libc.so.6, ##name) args
njn3e884182003-04-15 13:03:23 +000064
nethercoted6447b42004-07-15 16:28:36 +000065extern void _exit(int);
66
njn3e884182003-04-15 13:03:23 +000067/*------------------------------------------------------------*/
68/*--- Replacing malloc() et al ---*/
69/*------------------------------------------------------------*/
70
fitzhardinge98abfc72003-12-16 02:05:15 +000071static struct vg_mallocfunc_info info;
72static int init_done;
73
74/* Startup hook - called as init section */
75static void init(void) __attribute__((constructor));
76
njn3e884182003-04-15 13:03:23 +000077/* Below are new versions of malloc, __builtin_new, free,
78 __builtin_delete, calloc, realloc, memalign, and friends.
79
fitzhardinge98abfc72003-12-16 02:05:15 +000080 None of these functions are called directly - they are not meant to
81 be found by the dynamic linker. They get called because
82 vg_replace_malloc installs a bunch of code redirects which causes
83 Valgrind to use these functions rather than the ones they're
rjwalshe4e779d2004-04-16 23:02:29 +000084 replacing.
njn3e884182003-04-15 13:03:23 +000085*/
86
87#define MALLOC_TRACE(format, args...) \
fitzhardinge98abfc72003-12-16 02:05:15 +000088 if (info.clo_trace_malloc) \
fitzhardinge7fae3e02003-10-31 07:13:41 +000089 VALGRIND_INTERNAL_PRINTF(format, ## args )
njn3e884182003-04-15 13:03:23 +000090
91#define MAYBE_SLOPPIFY(n) \
fitzhardinge98abfc72003-12-16 02:05:15 +000092 if (info.clo_sloppy_malloc) { \
nethercote2d5b8162004-08-11 09:40:52 +000093 n = (n+(VG_SLOPPY_MALLOC_SZB-1)) & ~(VG_SLOPPY_MALLOC_SZB-1); \
njn3e884182003-04-15 13:03:23 +000094 }
95
njnd0eab5f2003-09-30 16:52:47 +000096/* ALL calls to malloc() and friends wind up here. */
97#define ALLOC(fff, vgfff) \
nethercote928a5f72004-11-03 18:10:37 +000098LIBALIAS(void *, fff, (SizeT n)) \
njnd0eab5f2003-09-30 16:52:47 +000099{ \
100 void* v; \
101 \
fitzhardinge98abfc72003-12-16 02:05:15 +0000102 MALLOC_TRACE(#fff "(%d)", n ); \
njnd0eab5f2003-09-30 16:52:47 +0000103 MAYBE_SLOPPIFY(n); \
fitzhardinge98abfc72003-12-16 02:05:15 +0000104 if (!init_done) init(); \
njnd0eab5f2003-09-30 16:52:47 +0000105 \
fitzhardinge98abfc72003-12-16 02:05:15 +0000106 v = (void*)VALGRIND_NON_SIMD_CALL1( info.sk_##vgfff, n ); \
fitzhardinge7fae3e02003-10-31 07:13:41 +0000107 MALLOC_TRACE(" = %p", v ); \
njnd0eab5f2003-09-30 16:52:47 +0000108 return v; \
njn3e884182003-04-15 13:03:23 +0000109}
nethercoted6447b42004-07-15 16:28:36 +0000110
111#define ALLOC2(fff, vgfff) \
nethercote928a5f72004-11-03 18:10:37 +0000112LIBALIAS(void *, fff, (SizeT n)) \
nethercoted6447b42004-07-15 16:28:36 +0000113{ \
114 void* v; \
115 \
116 MALLOC_TRACE(#fff "(%d)", n ); \
117 MAYBE_SLOPPIFY(n); \
118 if (!init_done) init(); \
119 \
120 v = (void*)VALGRIND_NON_SIMD_CALL1( info.sk_##vgfff, n ); \
121 MALLOC_TRACE(" = %p", v ); \
122 if (NULL == v) { \
123 VALGRIND_PRINTF_BACKTRACE( \
124 "new/new[] failed and should throw an exception, but Valgrind\n" \
125 " cannot throw exceptions and so is aborting instead. Sorry."); \
126 _exit(1); \
127 } \
128 return v; \
129}
fitzhardinge98abfc72003-12-16 02:05:15 +0000130ALLOC( malloc, malloc );
nethercoted6447b42004-07-15 16:28:36 +0000131ALLOC2(__builtin_new, __builtin_new );
132ALLOC2(_Znwj, __builtin_new );
njn5cebf572003-10-09 15:40:38 +0000133
134// operator new(unsigned, std::nothrow_t const&)
fitzhardinge98abfc72003-12-16 02:05:15 +0000135ALLOC( _ZnwjRKSt9nothrow_t, __builtin_new );
njn5cebf572003-10-09 15:40:38 +0000136
nethercoted6447b42004-07-15 16:28:36 +0000137ALLOC2(__builtin_vec_new, __builtin_vec_new );
138ALLOC2(_Znaj, __builtin_vec_new );
njn5cebf572003-10-09 15:40:38 +0000139
nethercoted6447b42004-07-15 16:28:36 +0000140// operator new[](unsigned, std::nothrow_t const&)
fitzhardinge98abfc72003-12-16 02:05:15 +0000141ALLOC( _ZnajRKSt9nothrow_t, __builtin_vec_new );
njn3e884182003-04-15 13:03:23 +0000142
njnd0eab5f2003-09-30 16:52:47 +0000143#define FREE(fff, vgfff) \
rjwalshe4e779d2004-04-16 23:02:29 +0000144LIBALIAS(void, fff, (void *p)) \
njnd0eab5f2003-09-30 16:52:47 +0000145{ \
fitzhardinge98abfc72003-12-16 02:05:15 +0000146 MALLOC_TRACE(#fff "(%p)", p ); \
njnd0eab5f2003-09-30 16:52:47 +0000147 if (p == NULL) \
148 return; \
fitzhardinge98abfc72003-12-16 02:05:15 +0000149 if (!init_done) init(); \
150 (void)VALGRIND_NON_SIMD_CALL1( info.sk_##vgfff, p ); \
njn3e884182003-04-15 13:03:23 +0000151}
fitzhardinge98abfc72003-12-16 02:05:15 +0000152FREE( free, free );
rjwalshe4e779d2004-04-16 23:02:29 +0000153FREE( cfree, free );
fitzhardinge98abfc72003-12-16 02:05:15 +0000154FREE( __builtin_delete, __builtin_delete );
155FREE( _ZdlPv, __builtin_delete );
nethercote23cd8c02004-07-14 15:38:06 +0000156
157// operator delete(void*, std::nothrow_t const&)
158FREE( _ZdlPvRKSt9nothrow_t, __builtin_delete );
159
fitzhardinge98abfc72003-12-16 02:05:15 +0000160FREE( __builtin_vec_delete, __builtin_vec_delete );
161FREE( _ZdaPv, __builtin_vec_delete );
njn3e884182003-04-15 13:03:23 +0000162
nethercote23cd8c02004-07-14 15:38:06 +0000163// operator delete[](void*, std::nothrow_t const&)
164FREE( _ZdaPvRKSt9nothrow_t, __builtin_vec_delete );
165
166
nethercote928a5f72004-11-03 18:10:37 +0000167LIBALIAS(void*, calloc, ( SizeT nmemb, SizeT size ))
njn3e884182003-04-15 13:03:23 +0000168{
169 void* v;
170
fitzhardinge98abfc72003-12-16 02:05:15 +0000171 MALLOC_TRACE("calloc(%d,%d)", nmemb, size );
njn3e884182003-04-15 13:03:23 +0000172 MAYBE_SLOPPIFY(size);
173
fitzhardinge98abfc72003-12-16 02:05:15 +0000174 if (!init_done) init();
175 v = (void*)VALGRIND_NON_SIMD_CALL2( info.sk_calloc, nmemb, size );
fitzhardinge7fae3e02003-10-31 07:13:41 +0000176 MALLOC_TRACE(" = %p", v );
njn3e884182003-04-15 13:03:23 +0000177 return v;
178}
179
nethercote928a5f72004-11-03 18:10:37 +0000180LIBALIAS(void*, realloc, ( void* ptrV, SizeT new_size ))
njn3e884182003-04-15 13:03:23 +0000181{
182 void* v;
183
fitzhardinge98abfc72003-12-16 02:05:15 +0000184 MALLOC_TRACE("realloc(%p,%d)", ptrV, new_size );
njn3e884182003-04-15 13:03:23 +0000185 MAYBE_SLOPPIFY(new_size);
186
187 if (ptrV == NULL)
rjwalshe4e779d2004-04-16 23:02:29 +0000188 return VG_INTERCEPT(soname:libc.so.6, malloc)(new_size);
njn3e884182003-04-15 13:03:23 +0000189 if (new_size <= 0) {
rjwalshe4e779d2004-04-16 23:02:29 +0000190 VG_INTERCEPT(soname:libc.so.6, free)(ptrV);
fitzhardinge98abfc72003-12-16 02:05:15 +0000191 if (info.clo_trace_malloc)
192 VALGRIND_INTERNAL_PRINTF(" = 0" );
njn3e884182003-04-15 13:03:23 +0000193 return NULL;
194 }
fitzhardinge98abfc72003-12-16 02:05:15 +0000195 if (!init_done) init();
196 v = (void*)VALGRIND_NON_SIMD_CALL2( info.sk_realloc, ptrV, new_size );
fitzhardinge7fae3e02003-10-31 07:13:41 +0000197 MALLOC_TRACE(" = %p", v );
njn3e884182003-04-15 13:03:23 +0000198 return v;
199}
200
201
nethercote928a5f72004-11-03 18:10:37 +0000202LIBALIAS(void*, memalign, ( SizeT alignment, SizeT n ))
njn3e884182003-04-15 13:03:23 +0000203{
204 void* v;
205
fitzhardinge98abfc72003-12-16 02:05:15 +0000206 MALLOC_TRACE("memalign(al %d, size %d)", alignment, n );
njn3e884182003-04-15 13:03:23 +0000207 MAYBE_SLOPPIFY(n);
208
nethercote2d5b8162004-08-11 09:40:52 +0000209 // Round up to minimum alignment if necessary.
210 if (alignment < VG_MIN_MALLOC_SZB) alignment = VG_MIN_MALLOC_SZB;
211
212 // Round up to nearest power-of-two if necessary (like glibc).
213 while (0 != (alignment & (alignment - 1))) alignment++;
214
fitzhardinge98abfc72003-12-16 02:05:15 +0000215 if (!init_done) init();
216 v = (void*)VALGRIND_NON_SIMD_CALL2( info.sk_memalign, alignment, n );
fitzhardinge7fae3e02003-10-31 07:13:41 +0000217 MALLOC_TRACE(" = %p", v );
njn3e884182003-04-15 13:03:23 +0000218 return v;
219}
220
221
nethercote928a5f72004-11-03 18:10:37 +0000222LIBALIAS(void*, valloc, ( SizeT size ))
njn3e884182003-04-15 13:03:23 +0000223{
nethercote5d4ac832004-10-31 18:58:05 +0000224 return VG_INTERCEPT(soname:libc.so.6, memalign)(VKI_PAGE_SIZE, size);
njn3e884182003-04-15 13:03:23 +0000225}
226
227
228/* Various compatibility wrapper functions, for glibc and libstdc++. */
fitzhardinge98abfc72003-12-16 02:05:15 +0000229
fitzhardinge98abfc72003-12-16 02:05:15 +0000230LIBALIAS(int, mallopt, ( int cmd, int value ))
njn3e884182003-04-15 13:03:23 +0000231{
232 /* In glibc-2.2.4, 1 denotes a successful return value for mallopt */
233 return 1;
234}
235
236
nethercote928a5f72004-11-03 18:10:37 +0000237LIBALIAS(int, posix_memalign, ( void **memptr, SizeT alignment, SizeT size ))
njn3e884182003-04-15 13:03:23 +0000238{
239 void *mem;
240
mueller211d05d2003-11-28 00:15:57 +0000241 /* Test whether the alignment argument is valid. It must be a power of
njn3e884182003-04-15 13:03:23 +0000242 two multiple of sizeof (void *). */
mueller211d05d2003-11-28 00:15:57 +0000243 if (alignment % sizeof (void *) != 0 || (alignment & (alignment - 1)) != 0)
njn3e884182003-04-15 13:03:23 +0000244 return VKI_EINVAL /*22*/ /*EINVAL*/;
245
rjwalshe4e779d2004-04-16 23:02:29 +0000246 mem = VG_INTERCEPT(soname:libc.so.6, memalign)(alignment, size);
njn3e884182003-04-15 13:03:23 +0000247
248 if (mem != NULL) {
249 *memptr = mem;
250 return 0;
251 }
252
253 return VKI_ENOMEM /*12*/ /*ENOMEM*/;
254}
255
fitzhardinge98abfc72003-12-16 02:05:15 +0000256LIBALIAS(int, malloc_usable_size, ( void* p ))
njn8a6b6c02003-04-22 22:45:55 +0000257{
nethercote928a5f72004-11-03 18:10:37 +0000258 SizeT pszB;
njn8a6b6c02003-04-22 22:45:55 +0000259
fitzhardinge98abfc72003-12-16 02:05:15 +0000260 MALLOC_TRACE("malloc_usable_size(%p)", p );
njn8a6b6c02003-04-22 22:45:55 +0000261 if (NULL == p)
262 return 0;
263
fitzhardinge98abfc72003-12-16 02:05:15 +0000264 if (!init_done) init();
nethercote928a5f72004-11-03 18:10:37 +0000265 pszB = (SizeT)VALGRIND_NON_SIMD_CALL2( info.arena_payload_szB,
266 VG_AR_CLIENT, p );
fitzhardinge7fae3e02003-10-31 07:13:41 +0000267 MALLOC_TRACE(" = %d", pszB );
njn8a6b6c02003-04-22 22:45:55 +0000268
269 return pszB;
270}
271
njn3e884182003-04-15 13:03:23 +0000272
273/* Bomb out if we get any of these. */
njn8a6b6c02003-04-22 22:45:55 +0000274
fitzhardinge98abfc72003-12-16 02:05:15 +0000275static void panic(const char *str)
276{
277 VALGRIND_PRINTF_BACKTRACE("Program aborting because of call to %s", str);
278
279 _exit(99);
280 *(int *)0 = 'x';
281}
282
rjwalshe4e779d2004-04-16 23:02:29 +0000283#define PANIC(x) \
284 void VG_INTERCEPT(soname:libc.so.6, ## x)(void) \
285 { \
286 panic(#x); \
fitzhardinge98abfc72003-12-16 02:05:15 +0000287 }
288
289PANIC(pvalloc);
290PANIC(malloc_stats);
291PANIC(malloc_trim);
292PANIC(malloc_get_state);
293PANIC(malloc_set_state);
njn3e884182003-04-15 13:03:23 +0000294
295
296/* Yet another ugly hack. Cannot include <malloc.h> because we
297 implement functions implemented there with different signatures.
298 This struct definition MUST match the system one. */
299
300/* SVID2/XPG mallinfo structure */
301struct mallinfo {
302 int arena; /* total space allocated from system */
303 int ordblks; /* number of non-inuse chunks */
304 int smblks; /* unused -- always zero */
305 int hblks; /* number of mmapped regions */
306 int hblkhd; /* total space in mmapped regions */
307 int usmblks; /* unused -- always zero */
308 int fsmblks; /* unused -- always zero */
309 int uordblks; /* total allocated space */
310 int fordblks; /* total non-inuse space */
311 int keepcost; /* top-most, releasable (via malloc_trim) space */
312};
313
fitzhardinge98abfc72003-12-16 02:05:15 +0000314LIBALIAS(struct mallinfo, mallinfo, ( void ))
njn3e884182003-04-15 13:03:23 +0000315{
316 /* Should really try to return something a bit more meaningful */
sewardj05bcdcb2003-05-18 10:05:38 +0000317 UInt i;
njn3e884182003-04-15 13:03:23 +0000318 struct mallinfo mi;
319 UChar* pmi = (UChar*)(&mi);
320 for (i = 0; i < sizeof(mi); i++)
321 pmi[i] = 0;
322 return mi;
323}
324
fitzhardinge98abfc72003-12-16 02:05:15 +0000325/* All the code in here is unused until this function is called */
326
327static void init(void)
328{
fitzhardinge98abfc72003-12-16 02:05:15 +0000329 int res;
330
331 if (init_done)
332 return;
333
334 init_done = 1;
335
rjwalshe4e779d2004-04-16 23:02:29 +0000336 VALGRIND_MAGIC_SEQUENCE(res, -1, VG_USERREQ__GET_MALLOCFUNCS, &info,
337 0, 0, 0);
fitzhardinge98abfc72003-12-16 02:05:15 +0000338}
339
njn3e884182003-04-15 13:03:23 +0000340/*--------------------------------------------------------------------*/
341/*--- end vg_replace_malloc.c ---*/
342/*--------------------------------------------------------------------*/