blob: 5510a06ffe1739f5c587e4674abae6b46b16ad15 [file] [log] [blame]
njn3e884182003-04-15 13:03:23 +00001
2/*--------------------------------------------------------------------*/
3/*--- malloc/free wrappers for detecting errors and updating bits. ---*/
4/*--- mac_malloc_wrappers.c ---*/
5/*--------------------------------------------------------------------*/
6
7/*
nethercote137bc552003-11-14 17:47:54 +00008 This file is part of MemCheck, a heavyweight Valgrind tool for
9 detecting memory errors, and AddrCheck, a lightweight Valgrind tool
njn3e884182003-04-15 13:03:23 +000010 for detecting memory errors.
11
njn53612422005-03-12 16:22:54 +000012 Copyright (C) 2000-2005 Julian Seward
njn3e884182003-04-15 13:03:23 +000013 jseward@acm.org
14
15 This program is free software; you can redistribute it and/or
16 modify it under the terms of the GNU General Public License as
17 published by the Free Software Foundation; either version 2 of the
18 License, or (at your option) any later version.
19
20 This program is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 General Public License for more details.
24
25 You should have received a copy of the GNU General Public License
26 along with this program; if not, write to the Free Software
27 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
28 02111-1307, USA.
29
30 The GNU General Public License is contained in the file COPYING.
31*/
32
33#include "mac_shared.h"
34
35/*------------------------------------------------------------*/
36/*--- Defns ---*/
37/*------------------------------------------------------------*/
38
39/* Stats ... */
nethercote7ac7f7b2004-11-02 12:36:02 +000040static SizeT cmalloc_n_mallocs = 0;
41static SizeT cmalloc_n_frees = 0;
42static SizeT cmalloc_bs_mallocd = 0;
njn3e884182003-04-15 13:03:23 +000043
44/* We want a 16B redzone on heap blocks for Addrcheck and Memcheck */
njn0e742df2004-11-30 13:26:29 +000045SizeT VG_(vg_malloc_redzone_szB) = 16;
njn3e884182003-04-15 13:03:23 +000046
nethercote7cc9c232004-01-21 15:08:04 +000047/* Function pointers for the two tools to track interesting events. */
nethercote451eae92004-11-02 13:06:32 +000048void (*MAC_(new_mem_heap)) ( Addr a, SizeT len, Bool is_inited ) = NULL;
49void (*MAC_(ban_mem_heap)) ( Addr a, SizeT len ) = NULL;
50void (*MAC_(die_mem_heap)) ( Addr a, SizeT len ) = NULL;
51void (*MAC_(copy_mem_heap))( Addr from, Addr to, SizeT len ) = NULL;
sewardjecf8e102003-07-12 12:11:39 +000052
53/* Function pointers for internal sanity checking. */
nethercote451eae92004-11-02 13:06:32 +000054Bool (*MAC_(check_noaccess))( Addr a, SizeT len, Addr* bad_addr ) = NULL;
sewardjf9025f72003-07-12 01:41:24 +000055
56
njn3e884182003-04-15 13:03:23 +000057/*------------------------------------------------------------*/
58/*--- Tracking malloc'd and free'd blocks ---*/
59/*------------------------------------------------------------*/
60
61/* Record malloc'd blocks. Nb: Addrcheck and Memcheck construct this
62 separately in their respective initialisation functions. */
63VgHashTable MAC_(malloc_list) = NULL;
rjwalshbc0bb832004-06-19 18:12:36 +000064
65/* Memory pools. Nb: Addrcheck and Memcheck construct this separately
66 in their respective initialisation functions. */
67VgHashTable MAC_(mempool_list) = NULL;
njn3e884182003-04-15 13:03:23 +000068
69/* Records blocks after freeing. */
70static MAC_Chunk* freed_list_start = NULL;
71static MAC_Chunk* freed_list_end = NULL;
72static Int freed_list_volume = 0;
73
74/* Put a shadow chunk on the freed blocks queue, possibly freeing up
75 some of the oldest blocks in the queue at the same time. */
76static void add_to_freed_queue ( MAC_Chunk* mc )
77{
78 MAC_Chunk* sc1;
79
80 /* Put it at the end of the freed list */
81 if (freed_list_end == NULL) {
njnca82cc02004-11-22 17:18:48 +000082 tl_assert(freed_list_start == NULL);
njn3e884182003-04-15 13:03:23 +000083 freed_list_end = freed_list_start = mc;
84 freed_list_volume = mc->size;
85 } else {
njnca82cc02004-11-22 17:18:48 +000086 tl_assert(freed_list_end->next == NULL);
njn3e884182003-04-15 13:03:23 +000087 freed_list_end->next = mc;
88 freed_list_end = mc;
89 freed_list_volume += mc->size;
90 }
91 mc->next = NULL;
92
93 /* Release enough of the oldest blocks to bring the free queue
94 volume below vg_clo_freelist_vol. */
95
96 while (freed_list_volume > MAC_(clo_freelist_vol)) {
njnca82cc02004-11-22 17:18:48 +000097 tl_assert(freed_list_start != NULL);
98 tl_assert(freed_list_end != NULL);
njn3e884182003-04-15 13:03:23 +000099
100 sc1 = freed_list_start;
101 freed_list_volume -= sc1->size;
102 /* VG_(printf)("volume now %d\n", freed_list_volume); */
njnca82cc02004-11-22 17:18:48 +0000103 tl_assert(freed_list_volume >= 0);
njn3e884182003-04-15 13:03:23 +0000104
105 if (freed_list_start == freed_list_end) {
106 freed_list_start = freed_list_end = NULL;
107 } else {
108 freed_list_start = sc1->next;
109 }
110 sc1->next = NULL; /* just paranoia */
111
112 /* free MAC_Chunk */
113 VG_(cli_free) ( (void*)(sc1->data) );
114 VG_(free) ( sc1 );
115 }
116}
117
118/* Return the first shadow chunk satisfying the predicate p. */
thughes4ad52d02004-06-27 17:37:21 +0000119MAC_Chunk* MAC_(first_matching_freed_MAC_Chunk) ( Bool (*p)(MAC_Chunk*, void*),
120 void* d )
njn3e884182003-04-15 13:03:23 +0000121{
122 MAC_Chunk* mc;
123
124 /* No point looking through freed blocks if we're not keeping
125 them around for a while... */
126 for (mc = freed_list_start; mc != NULL; mc = mc->next)
thughes4ad52d02004-06-27 17:37:21 +0000127 if (p(mc, d))
njn3e884182003-04-15 13:03:23 +0000128 return mc;
129
130 return NULL;
131}
132
njn10785452003-05-20 16:38:24 +0000133/* Allocate its shadow chunk, put it on the appropriate list. */
134static
sewardj2a99cf62004-11-24 10:44:19 +0000135void add_MAC_Chunk ( ThreadId tid,
136 Addr p, SizeT size, MAC_AllocKind kind, VgHashTable table)
njn3e884182003-04-15 13:03:23 +0000137{
138 MAC_Chunk* mc;
139
140 mc = VG_(malloc)(sizeof(MAC_Chunk));
141 mc->data = p;
142 mc->size = size;
143 mc->allockind = kind;
njnd01fef72005-03-25 23:35:48 +0000144 mc->where = VG_(record_ExeContext)(tid);
njn3e884182003-04-15 13:03:23 +0000145
sewardjecf8e102003-07-12 12:11:39 +0000146 /* Paranoia ... ensure this area is off-limits to the client, so
147 the mc->data field isn't visible to the leak checker. If memory
148 management is working correctly, anything pointer returned by
149 VG_(malloc) should be noaccess as far as the client is
150 concerned. */
151 if (!MAC_(check_noaccess)( (Addr)mc, sizeof(MAC_Chunk), NULL )) {
sewardj2a99cf62004-11-24 10:44:19 +0000152 VG_(tool_panic)("add_MAC_Chunk: shadow area is accessible");
sewardjecf8e102003-07-12 12:11:39 +0000153 }
sewardjf9025f72003-07-12 01:41:24 +0000154
rjwalshbc0bb832004-06-19 18:12:36 +0000155 VG_(HT_add_node)( table, (VgHashNode*)mc );
njn3e884182003-04-15 13:03:23 +0000156}
157
158/*------------------------------------------------------------*/
159/*--- client_malloc(), etc ---*/
160/*------------------------------------------------------------*/
161
nethercote7ac7f7b2004-11-02 12:36:02 +0000162static Bool complain_about_silly_args(SizeT sizeB, Char* fn)
163{
164 // Cast to a signed type to catch any unexpectedly negative args. We're
165 // assuming here that the size asked for is not greater than 2^31 bytes
166 // (for 32-bit platforms) or 2^63 bytes (for 64-bit platforms).
167 if ((SSizeT)sizeB < 0) {
168 VG_(message)(Vg_UserMsg, "Warning: silly arg (%d) to %s()", sizeB, fn );
169 return True;
170 }
171 return False;
172}
173
174static Bool complain_about_silly_args2(SizeT n, SizeT sizeB)
175{
176 if ((SSizeT)n < 0 || (SSizeT)sizeB < 0) {
177 VG_(message)(Vg_UserMsg, "Warning: silly args (%d,%d) to calloc()",
178 n, sizeB);
179 return True;
180 }
181 return False;
182}
183
njn3e884182003-04-15 13:03:23 +0000184/* Allocate memory and note change in memory available */
njn10785452003-05-20 16:38:24 +0000185__inline__
sewardj2a99cf62004-11-24 10:44:19 +0000186void* MAC_(new_block) ( ThreadId tid,
187 Addr p, SizeT size, SizeT align, UInt rzB,
nethercote57e36b32004-07-10 14:56:28 +0000188 Bool is_zeroed, MAC_AllocKind kind, VgHashTable table)
njn3e884182003-04-15 13:03:23 +0000189{
njn3e884182003-04-15 13:03:23 +0000190 VGP_PUSHCC(VgpCliMalloc);
njn3e884182003-04-15 13:03:23 +0000191 cmalloc_n_mallocs ++;
192 cmalloc_bs_mallocd += size;
193
nethercote57e36b32004-07-10 14:56:28 +0000194 // Allocate and zero if necessary
195 if (p) {
njnca82cc02004-11-22 17:18:48 +0000196 tl_assert(MAC_AllocCustom == kind);
nethercote57e36b32004-07-10 14:56:28 +0000197 } else {
njnca82cc02004-11-22 17:18:48 +0000198 tl_assert(MAC_AllocCustom != kind);
nethercote57e36b32004-07-10 14:56:28 +0000199 p = (Addr)VG_(cli_malloc)( align, size );
200 if (!p) {
201 VGP_POPCC(VgpCliMalloc);
202 return NULL;
203 }
204 if (is_zeroed) VG_(memset)((void*)p, 0, size);
205 }
206
sewardj2a99cf62004-11-24 10:44:19 +0000207 add_MAC_Chunk( tid, p, size, kind, table );
njn3e884182003-04-15 13:03:23 +0000208
njn10785452003-05-20 16:38:24 +0000209 MAC_(ban_mem_heap)( p-rzB, rzB );
njn3e884182003-04-15 13:03:23 +0000210 MAC_(new_mem_heap)( p, size, is_zeroed );
njn10785452003-05-20 16:38:24 +0000211 MAC_(ban_mem_heap)( p+size, rzB );
njn3e884182003-04-15 13:03:23 +0000212
213 VGP_POPCC(VgpCliMalloc);
rjwalshbc0bb832004-06-19 18:12:36 +0000214
nethercote57e36b32004-07-10 14:56:28 +0000215 return (void*)p;
njn3e884182003-04-15 13:03:23 +0000216}
217
sewardj2a99cf62004-11-24 10:44:19 +0000218void* TL_(malloc) ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +0000219{
nethercote7ac7f7b2004-11-02 12:36:02 +0000220 if (complain_about_silly_args(n, "malloc")) {
njn3e884182003-04-15 13:03:23 +0000221 return NULL;
222 } else {
sewardj2a99cf62004-11-24 10:44:19 +0000223 return MAC_(new_block) ( tid, 0, n, VG_(clo_alignment),
nethercote57e36b32004-07-10 14:56:28 +0000224 VG_(vg_malloc_redzone_szB), /*is_zeroed*/False, MAC_AllocMalloc,
225 MAC_(malloc_list));
njn3e884182003-04-15 13:03:23 +0000226 }
227}
228
sewardj2a99cf62004-11-24 10:44:19 +0000229void* TL_(__builtin_new) ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +0000230{
nethercote7ac7f7b2004-11-02 12:36:02 +0000231 if (complain_about_silly_args(n, "__builtin_new")) {
njn3e884182003-04-15 13:03:23 +0000232 return NULL;
233 } else {
sewardj2a99cf62004-11-24 10:44:19 +0000234 return MAC_(new_block) ( tid, 0, n, VG_(clo_alignment),
nethercote57e36b32004-07-10 14:56:28 +0000235 VG_(vg_malloc_redzone_szB), /*is_zeroed*/False, MAC_AllocNew,
236 MAC_(malloc_list));
njn3e884182003-04-15 13:03:23 +0000237 }
238}
239
sewardj2a99cf62004-11-24 10:44:19 +0000240void* TL_(__builtin_vec_new) ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +0000241{
nethercote7ac7f7b2004-11-02 12:36:02 +0000242 if (complain_about_silly_args(n, "__builtin_vec_new")) {
njn3e884182003-04-15 13:03:23 +0000243 return NULL;
244 } else {
sewardj2a99cf62004-11-24 10:44:19 +0000245 return MAC_(new_block) ( tid, 0, n, VG_(clo_alignment),
nethercote57e36b32004-07-10 14:56:28 +0000246 VG_(vg_malloc_redzone_szB), /*is_zeroed*/False, MAC_AllocNewVec,
247 MAC_(malloc_list));
njn3e884182003-04-15 13:03:23 +0000248 }
249}
250
sewardj2a99cf62004-11-24 10:44:19 +0000251void* TL_(memalign) ( ThreadId tid, SizeT align, SizeT n )
njn3e884182003-04-15 13:03:23 +0000252{
nethercote7ac7f7b2004-11-02 12:36:02 +0000253 if (complain_about_silly_args(n, "memalign")) {
njn3e884182003-04-15 13:03:23 +0000254 return NULL;
255 } else {
sewardj2a99cf62004-11-24 10:44:19 +0000256 return MAC_(new_block) ( tid, 0, n, align,
nethercote57e36b32004-07-10 14:56:28 +0000257 VG_(vg_malloc_redzone_szB), /*is_zeroed*/False, MAC_AllocMalloc,
258 MAC_(malloc_list));
njn3e884182003-04-15 13:03:23 +0000259 }
260}
261
sewardj2a99cf62004-11-24 10:44:19 +0000262void* TL_(calloc) ( ThreadId tid, SizeT nmemb, SizeT size1 )
njn3e884182003-04-15 13:03:23 +0000263{
nethercote7ac7f7b2004-11-02 12:36:02 +0000264 if (complain_about_silly_args2(nmemb, size1)) {
njn3e884182003-04-15 13:03:23 +0000265 return NULL;
266 } else {
sewardj2a99cf62004-11-24 10:44:19 +0000267 return MAC_(new_block) ( tid, 0, nmemb*size1, VG_(clo_alignment),
nethercote57e36b32004-07-10 14:56:28 +0000268 VG_(vg_malloc_redzone_szB), /*is_zeroed*/True, MAC_AllocMalloc,
269 MAC_(malloc_list));
njn3e884182003-04-15 13:03:23 +0000270 }
271}
272
273static
sewardj2a99cf62004-11-24 10:44:19 +0000274void die_and_free_mem ( ThreadId tid,
275 MAC_Chunk* mc,
nethercote7ac7f7b2004-11-02 12:36:02 +0000276 MAC_Chunk** prev_chunks_next_ptr, SizeT rzB )
njn3e884182003-04-15 13:03:23 +0000277{
278 /* Note: ban redzones again -- just in case user de-banned them
279 with a client request... */
njn10785452003-05-20 16:38:24 +0000280 MAC_(ban_mem_heap)( mc->data-rzB, rzB );
njn3e884182003-04-15 13:03:23 +0000281 MAC_(die_mem_heap)( mc->data, mc->size );
njn10785452003-05-20 16:38:24 +0000282 MAC_(ban_mem_heap)( mc->data+mc->size, rzB );
njn3e884182003-04-15 13:03:23 +0000283
284 /* Remove mc from the malloclist using prev_chunks_next_ptr to
285 avoid repeating the hash table lookup. Can't remove until at least
286 after free and free_mismatch errors are done because they use
287 describe_addr() which looks for it in malloclist. */
288 *prev_chunks_next_ptr = mc->next;
289
njn10785452003-05-20 16:38:24 +0000290 /* Put it out of harm's way for a while, if not from a client request */
rjwalshbc0bb832004-06-19 18:12:36 +0000291 if (MAC_AllocCustom != mc->allockind) {
292 /* Record where freed */
njnd01fef72005-03-25 23:35:48 +0000293 mc->where = VG_(record_ExeContext) ( tid );
njn10785452003-05-20 16:38:24 +0000294 add_to_freed_queue ( mc );
rjwalshbc0bb832004-06-19 18:12:36 +0000295 } else
njn10785452003-05-20 16:38:24 +0000296 VG_(free) ( mc );
njn3e884182003-04-15 13:03:23 +0000297}
298
njn10785452003-05-20 16:38:24 +0000299__inline__
sewardj2a99cf62004-11-24 10:44:19 +0000300void MAC_(handle_free) ( ThreadId tid, Addr p, UInt rzB, MAC_AllocKind kind )
njn3e884182003-04-15 13:03:23 +0000301{
302 MAC_Chunk* mc;
303 MAC_Chunk** prev_chunks_next_ptr;
304
305 VGP_PUSHCC(VgpCliMalloc);
306
307 cmalloc_n_frees++;
308
nethercote3d6b6112004-11-04 16:39:43 +0000309 mc = (MAC_Chunk*)VG_(HT_get_node) ( MAC_(malloc_list), (UWord)p,
nethercote76c65502004-10-25 19:46:07 +0000310 (void*)&prev_chunks_next_ptr );
njn3e884182003-04-15 13:03:23 +0000311 if (mc == NULL) {
njn72718642003-07-24 08:45:32 +0000312 MAC_(record_free_error) ( tid, p );
njn3e884182003-04-15 13:03:23 +0000313 VGP_POPCC(VgpCliMalloc);
314 return;
315 }
316
317 /* check if its a matching free() / delete / delete [] */
318 if (kind != mc->allockind) {
njn72718642003-07-24 08:45:32 +0000319 MAC_(record_freemismatch_error) ( tid, p );
njn3e884182003-04-15 13:03:23 +0000320 }
321
sewardj2a99cf62004-11-24 10:44:19 +0000322 die_and_free_mem ( tid, mc, prev_chunks_next_ptr, rzB );
njn3e884182003-04-15 13:03:23 +0000323 VGP_POPCC(VgpCliMalloc);
324}
325
sewardj2a99cf62004-11-24 10:44:19 +0000326void TL_(free) ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +0000327{
sewardj2a99cf62004-11-24 10:44:19 +0000328 MAC_(handle_free)(
329 tid, (Addr)p, VG_(vg_malloc_redzone_szB), MAC_AllocMalloc );
njn3e884182003-04-15 13:03:23 +0000330}
331
sewardj2a99cf62004-11-24 10:44:19 +0000332void TL_(__builtin_delete) ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +0000333{
sewardj2a99cf62004-11-24 10:44:19 +0000334 MAC_(handle_free)(
335 tid, (Addr)p, VG_(vg_malloc_redzone_szB), MAC_AllocNew);
njn3e884182003-04-15 13:03:23 +0000336}
337
sewardj2a99cf62004-11-24 10:44:19 +0000338void TL_(__builtin_vec_delete) ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +0000339{
sewardj2a99cf62004-11-24 10:44:19 +0000340 MAC_(handle_free)(
341 tid, (Addr)p, VG_(vg_malloc_redzone_szB), MAC_AllocNewVec);
njn3e884182003-04-15 13:03:23 +0000342}
343
sewardj2a99cf62004-11-24 10:44:19 +0000344void* TL_(realloc) ( ThreadId tid, void* p, SizeT new_size )
njn3e884182003-04-15 13:03:23 +0000345{
346 MAC_Chunk *mc;
347 MAC_Chunk **prev_chunks_next_ptr;
348 UInt i;
349
350 VGP_PUSHCC(VgpCliMalloc);
351
352 cmalloc_n_frees ++;
353 cmalloc_n_mallocs ++;
354 cmalloc_bs_mallocd += new_size;
355
nethercote7ac7f7b2004-11-02 12:36:02 +0000356 if (complain_about_silly_args(new_size, "realloc"))
njn3e884182003-04-15 13:03:23 +0000357 return NULL;
njn3e884182003-04-15 13:03:23 +0000358
359 /* First try and find the block. */
nethercote3d6b6112004-11-04 16:39:43 +0000360 mc = (MAC_Chunk*)VG_(HT_get_node) ( MAC_(malloc_list), (UWord)p,
nethercote76c65502004-10-25 19:46:07 +0000361 (void*)&prev_chunks_next_ptr );
njn3e884182003-04-15 13:03:23 +0000362
363 if (mc == NULL) {
njn72718642003-07-24 08:45:32 +0000364 MAC_(record_free_error) ( tid, (Addr)p );
njn3e884182003-04-15 13:03:23 +0000365 /* Perhaps we should return to the program regardless. */
366 VGP_POPCC(VgpCliMalloc);
367 return NULL;
368 }
369
370 /* check if its a matching free() / delete / delete [] */
371 if (MAC_AllocMalloc != mc->allockind) {
372 /* can not realloc a range that was allocated with new or new [] */
njn72718642003-07-24 08:45:32 +0000373 MAC_(record_freemismatch_error) ( tid, (Addr)p );
njn3e884182003-04-15 13:03:23 +0000374 /* but keep going anyway */
375 }
376
377 if (mc->size == new_size) {
378 /* size unchanged */
njnd01fef72005-03-25 23:35:48 +0000379 mc->where = VG_(record_ExeContext)(tid);
njn3e884182003-04-15 13:03:23 +0000380 VGP_POPCC(VgpCliMalloc);
381 return p;
382
383 } else if (mc->size > new_size) {
384 /* new size is smaller */
385 MAC_(die_mem_heap)( mc->data+new_size, mc->size-new_size );
386 mc->size = new_size;
njnd01fef72005-03-25 23:35:48 +0000387 mc->where = VG_(record_ExeContext)(tid);
njn3e884182003-04-15 13:03:23 +0000388 VGP_POPCC(VgpCliMalloc);
389 return p;
390
391 } else {
392 /* new size is bigger */
393 Addr p_new;
394
395 /* Get new memory */
396 p_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size);
397
398 /* First half kept and copied, second half new,
399 red zones as normal */
400 MAC_(ban_mem_heap) ( p_new-VG_(vg_malloc_redzone_szB),
401 VG_(vg_malloc_redzone_szB) );
402 MAC_(copy_mem_heap)( (Addr)p, p_new, mc->size );
403 MAC_(new_mem_heap) ( p_new+mc->size, new_size-mc->size, /*inited*/False );
404 MAC_(ban_mem_heap) ( p_new+new_size, VG_(vg_malloc_redzone_szB) );
405
406 /* Copy from old to new */
407 for (i = 0; i < mc->size; i++)
408 ((UChar*)p_new)[i] = ((UChar*)p)[i];
409
410 /* Free old memory */
sewardj2a99cf62004-11-24 10:44:19 +0000411 die_and_free_mem ( tid, mc, prev_chunks_next_ptr,
njn10785452003-05-20 16:38:24 +0000412 VG_(vg_malloc_redzone_szB) );
njn3e884182003-04-15 13:03:23 +0000413
414 /* this has to be after die_and_free_mem, otherwise the
415 former succeeds in shorting out the new block, not the
416 old, in the case when both are on the same list. */
sewardj2a99cf62004-11-24 10:44:19 +0000417 add_MAC_Chunk ( tid, p_new, new_size,
418 MAC_AllocMalloc, MAC_(malloc_list) );
njn3e884182003-04-15 13:03:23 +0000419
420 VGP_POPCC(VgpCliMalloc);
421 return (void*)p_new;
422 }
423}
424
rjwalshbc0bb832004-06-19 18:12:36 +0000425/* Memory pool stuff. */
426
427void MAC_(create_mempool)(Addr pool, UInt rzB, Bool is_zeroed)
428{
429 MAC_Mempool* mp;
430
431 mp = VG_(malloc)(sizeof(MAC_Mempool));
432 mp->pool = pool;
433 mp->rzB = rzB;
434 mp->is_zeroed = is_zeroed;
435 mp->chunks = VG_(HT_construct)();
436
437 /* Paranoia ... ensure this area is off-limits to the client, so
438 the mp->data field isn't visible to the leak checker. If memory
439 management is working correctly, anything pointer returned by
440 VG_(malloc) should be noaccess as far as the client is
441 concerned. */
442 if (!MAC_(check_noaccess)( (Addr)mp, sizeof(MAC_Mempool), NULL )) {
njn67993252004-11-22 18:02:32 +0000443 VG_(tool_panic)("MAC_(create_mempool): shadow area is accessible");
rjwalshbc0bb832004-06-19 18:12:36 +0000444 }
445
446 VG_(HT_add_node)( MAC_(mempool_list), (VgHashNode*)mp );
447
448}
449
thughes4ad52d02004-06-27 17:37:21 +0000450static void destroy_mempool_nuke_chunk(VgHashNode *node, void *d)
451{
452 MAC_Chunk *mc = (MAC_Chunk *)node;
453 MAC_Mempool *mp = (MAC_Mempool *)d;
454
455 /* Note: ban redzones again -- just in case user de-banned them
456 with a client request... */
457 MAC_(ban_mem_heap)(mc->data-mp->rzB, mp->rzB );
458 MAC_(die_mem_heap)(mc->data, mc->size );
459 MAC_(ban_mem_heap)(mc->data+mc->size, mp->rzB );
460}
461
rjwalshbc0bb832004-06-19 18:12:36 +0000462void MAC_(destroy_mempool)(Addr pool)
463{
thughes4ad52d02004-06-27 17:37:21 +0000464 MAC_Mempool* mp;
rjwalshbc0bb832004-06-19 18:12:36 +0000465 MAC_Mempool** prev_next;
466
thughes4ad52d02004-06-27 17:37:21 +0000467 mp = (MAC_Mempool*)VG_(HT_get_node) ( MAC_(mempool_list),
nethercote3d6b6112004-11-04 16:39:43 +0000468 (UWord)pool,
nethercote76c65502004-10-25 19:46:07 +0000469 (void*)&prev_next );
rjwalshbc0bb832004-06-19 18:12:36 +0000470
471 if (mp == NULL) {
sewardj76754cf2005-03-14 00:14:04 +0000472 ThreadId tid = VG_(get_running_tid)();
rjwalshbc0bb832004-06-19 18:12:36 +0000473
474 MAC_(record_illegal_mempool_error) ( tid, pool );
475 return;
476 }
477
478 *prev_next = mp->next;
thughes4ad52d02004-06-27 17:37:21 +0000479 VG_(HT_apply_to_all_nodes)(mp->chunks, destroy_mempool_nuke_chunk, mp);
rjwalshbc0bb832004-06-19 18:12:36 +0000480 VG_(HT_destruct)(mp->chunks);
481
482 VG_(free)(mp);
483}
484
sewardj2a99cf62004-11-24 10:44:19 +0000485void MAC_(mempool_alloc)(ThreadId tid, Addr pool, Addr addr, SizeT size)
rjwalshbc0bb832004-06-19 18:12:36 +0000486{
487 MAC_Mempool* mp;
488 MAC_Mempool** prev_next;
rjwalshbc0bb832004-06-19 18:12:36 +0000489
nethercote3d6b6112004-11-04 16:39:43 +0000490 mp = (MAC_Mempool*)VG_(HT_get_node) ( MAC_(mempool_list), (UWord)pool,
nethercote76c65502004-10-25 19:46:07 +0000491 (void*)&prev_next );
rjwalshbc0bb832004-06-19 18:12:36 +0000492
493 if (mp == NULL) {
rjwalshbc0bb832004-06-19 18:12:36 +0000494 MAC_(record_illegal_mempool_error) ( tid, pool );
495 return;
496 }
497
sewardj2a99cf62004-11-24 10:44:19 +0000498 MAC_(new_block)(tid, addr, size, /*ignored*/0, mp->rzB, mp->is_zeroed,
nethercote57e36b32004-07-10 14:56:28 +0000499 MAC_AllocCustom, mp->chunks);
rjwalshbc0bb832004-06-19 18:12:36 +0000500}
501
502void MAC_(mempool_free)(Addr pool, Addr addr)
503{
504 MAC_Mempool* mp;
505 MAC_Mempool** prev_pool;
506 MAC_Chunk* mc;
507 MAC_Chunk** prev_chunk;
sewardj76754cf2005-03-14 00:14:04 +0000508 ThreadId tid = VG_(get_running_tid)();
rjwalshbc0bb832004-06-19 18:12:36 +0000509
nethercote3d6b6112004-11-04 16:39:43 +0000510 mp = (MAC_Mempool*)VG_(HT_get_node)(MAC_(mempool_list), (UWord)pool,
nethercote76c65502004-10-25 19:46:07 +0000511 (void*)&prev_pool);
rjwalshbc0bb832004-06-19 18:12:36 +0000512
513 if (mp == NULL) {
514 MAC_(record_illegal_mempool_error)(tid, pool);
515 return;
516 }
517
nethercote3d6b6112004-11-04 16:39:43 +0000518 mc = (MAC_Chunk*)VG_(HT_get_node)(mp->chunks, (UWord)addr,
nethercote76c65502004-10-25 19:46:07 +0000519 (void*)&prev_chunk);
rjwalshbc0bb832004-06-19 18:12:36 +0000520
521 if (mc == NULL) {
522 MAC_(record_free_error)(tid, (Addr)addr);
523 return;
524 }
525
sewardj2a99cf62004-11-24 10:44:19 +0000526 die_and_free_mem ( tid, mc, prev_chunk, mp->rzB );
rjwalshbc0bb832004-06-19 18:12:36 +0000527}
528
njn86f12dc2005-03-14 01:16:05 +0000529/*------------------------------------------------------------*/
530/*--- Statistics printing ---*/
531/*------------------------------------------------------------*/
532
533typedef
534 struct {
535 UInt nblocks;
536 SizeT nbytes;
537 }
538 MallocStats;
539
540static void malloc_stats_count_chunk(VgHashNode* node, void* d) {
541 MAC_Chunk* mc = (MAC_Chunk*)node;
542 MallocStats *ms = (MallocStats *)d;
543
544 ms->nblocks ++;
545 ms->nbytes += mc->size;
546}
547
548void MAC_(print_malloc_stats) ( void )
549{
550 MallocStats ms;
551
552 ms.nblocks = 0;
553 ms.nbytes = 0;
554
555 if (VG_(clo_verbosity) == 0)
556 return;
557
558 /* Count memory still in use. */
559 VG_(HT_apply_to_all_nodes)(MAC_(malloc_list), malloc_stats_count_chunk, &ms);
560
561 VG_(message)(Vg_UserMsg,
562 "malloc/free: in use at exit: %d bytes in %d blocks.",
563 ms.nbytes, ms.nblocks);
564 VG_(message)(Vg_UserMsg,
565 "malloc/free: %d allocs, %d frees, %u bytes allocated.",
566 cmalloc_n_mallocs,
567 cmalloc_n_frees, cmalloc_bs_mallocd);
568 if (VG_(clo_verbosity) > 1)
569 VG_(message)(Vg_UserMsg, "");
570}
571
njn3e884182003-04-15 13:03:23 +0000572/*--------------------------------------------------------------------*/
njn86f12dc2005-03-14 01:16:05 +0000573/*--- end ---*/
njn3e884182003-04-15 13:03:23 +0000574/*--------------------------------------------------------------------*/