blob: de6d7e1508aff0f4f2816704db53418ceb8b2cb0 [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
njnc7561b92005-06-19 01:24:32 +000033#include "pub_tool_basics.h"
34#include "pub_tool_errormgr.h" // For mac_shared.h
35#include "pub_tool_execontext.h" // For mac_shared.h
36#include "pub_tool_hashtable.h" // For mac_shared.h
njn97405b22005-06-02 03:39:33 +000037#include "pub_tool_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000038#include "pub_tool_libcassert.h"
njn36a20fa2005-06-03 03:08:39 +000039#include "pub_tool_libcprint.h"
njnc7561b92005-06-19 01:24:32 +000040#include "pub_tool_mallocfree.h"
41#include "pub_tool_options.h"
42#include "pub_tool_profile.h" // For mac_shared.h
43#include "pub_tool_replacemalloc.h"
44#include "pub_tool_threadstate.h"
45#include "mac_shared.h"
njn3e884182003-04-15 13:03:23 +000046
47/*------------------------------------------------------------*/
48/*--- Defns ---*/
49/*------------------------------------------------------------*/
50
51/* Stats ... */
nethercote7ac7f7b2004-11-02 12:36:02 +000052static SizeT cmalloc_n_mallocs = 0;
53static SizeT cmalloc_n_frees = 0;
54static SizeT cmalloc_bs_mallocd = 0;
njn3e884182003-04-15 13:03:23 +000055
nethercote7cc9c232004-01-21 15:08:04 +000056/* Function pointers for the two tools to track interesting events. */
nethercote451eae92004-11-02 13:06:32 +000057void (*MAC_(new_mem_heap)) ( Addr a, SizeT len, Bool is_inited ) = NULL;
58void (*MAC_(ban_mem_heap)) ( Addr a, SizeT len ) = NULL;
59void (*MAC_(die_mem_heap)) ( Addr a, SizeT len ) = NULL;
60void (*MAC_(copy_mem_heap))( Addr from, Addr to, SizeT len ) = NULL;
sewardjecf8e102003-07-12 12:11:39 +000061
62/* Function pointers for internal sanity checking. */
nethercote451eae92004-11-02 13:06:32 +000063Bool (*MAC_(check_noaccess))( Addr a, SizeT len, Addr* bad_addr ) = NULL;
sewardjf9025f72003-07-12 01:41:24 +000064
65
njn3e884182003-04-15 13:03:23 +000066/*------------------------------------------------------------*/
67/*--- Tracking malloc'd and free'd blocks ---*/
68/*------------------------------------------------------------*/
69
njn9a463242005-08-16 03:29:50 +000070/* Record malloc'd blocks. */
njn3e884182003-04-15 13:03:23 +000071VgHashTable MAC_(malloc_list) = NULL;
rjwalshbc0bb832004-06-19 18:12:36 +000072
njn9a463242005-08-16 03:29:50 +000073/* Memory pools. */
rjwalshbc0bb832004-06-19 18:12:36 +000074VgHashTable MAC_(mempool_list) = NULL;
njn3e884182003-04-15 13:03:23 +000075
76/* Records blocks after freeing. */
77static MAC_Chunk* freed_list_start = NULL;
78static MAC_Chunk* freed_list_end = NULL;
79static Int freed_list_volume = 0;
80
81/* Put a shadow chunk on the freed blocks queue, possibly freeing up
82 some of the oldest blocks in the queue at the same time. */
83static void add_to_freed_queue ( MAC_Chunk* mc )
84{
njn3e884182003-04-15 13:03:23 +000085 /* Put it at the end of the freed list */
86 if (freed_list_end == NULL) {
njnca82cc02004-11-22 17:18:48 +000087 tl_assert(freed_list_start == NULL);
njn3e884182003-04-15 13:03:23 +000088 freed_list_end = freed_list_start = mc;
89 freed_list_volume = mc->size;
90 } else {
njnca82cc02004-11-22 17:18:48 +000091 tl_assert(freed_list_end->next == NULL);
njn3e884182003-04-15 13:03:23 +000092 freed_list_end->next = mc;
93 freed_list_end = mc;
94 freed_list_volume += mc->size;
95 }
96 mc->next = NULL;
97
98 /* Release enough of the oldest blocks to bring the free queue
99 volume below vg_clo_freelist_vol. */
100
101 while (freed_list_volume > MAC_(clo_freelist_vol)) {
njn9a463242005-08-16 03:29:50 +0000102 MAC_Chunk* mc1;
103
njnca82cc02004-11-22 17:18:48 +0000104 tl_assert(freed_list_start != NULL);
105 tl_assert(freed_list_end != NULL);
njn3e884182003-04-15 13:03:23 +0000106
njn5cc5d7e2005-08-11 02:09:25 +0000107 mc1 = freed_list_start;
108 freed_list_volume -= mc1->size;
njn3e884182003-04-15 13:03:23 +0000109 /* VG_(printf)("volume now %d\n", freed_list_volume); */
njnca82cc02004-11-22 17:18:48 +0000110 tl_assert(freed_list_volume >= 0);
njn3e884182003-04-15 13:03:23 +0000111
112 if (freed_list_start == freed_list_end) {
113 freed_list_start = freed_list_end = NULL;
114 } else {
njn5cc5d7e2005-08-11 02:09:25 +0000115 freed_list_start = mc1->next;
njn3e884182003-04-15 13:03:23 +0000116 }
njn5cc5d7e2005-08-11 02:09:25 +0000117 mc1->next = NULL; /* just paranoia */
njn3e884182003-04-15 13:03:23 +0000118
119 /* free MAC_Chunk */
njn5cc5d7e2005-08-11 02:09:25 +0000120 VG_(cli_free) ( (void*)(mc1->data) );
121 VG_(free) ( mc1 );
njn3e884182003-04-15 13:03:23 +0000122 }
123}
124
njn1d0cb0d2005-08-15 01:52:02 +0000125MAC_Chunk* MAC_(get_freed_list_head)(void)
njn3e884182003-04-15 13:03:23 +0000126{
njn1d0cb0d2005-08-15 01:52:02 +0000127 return freed_list_start;
njn3e884182003-04-15 13:03:23 +0000128}
129
njn10785452003-05-20 16:38:24 +0000130/* Allocate its shadow chunk, put it on the appropriate list. */
131static
njn5cc5d7e2005-08-11 02:09:25 +0000132MAC_Chunk* create_MAC_Chunk ( ThreadId tid, Addr p, SizeT size,
133 MAC_AllocKind kind)
njn3e884182003-04-15 13:03:23 +0000134{
njn5cc5d7e2005-08-11 02:09:25 +0000135 MAC_Chunk* mc = VG_(malloc)(sizeof(MAC_Chunk));
njn3e884182003-04-15 13:03:23 +0000136 mc->data = p;
137 mc->size = size;
138 mc->allockind = kind;
njnd01fef72005-03-25 23:35:48 +0000139 mc->where = VG_(record_ExeContext)(tid);
njn3e884182003-04-15 13:03:23 +0000140
njn9a463242005-08-16 03:29:50 +0000141 /* Paranoia ... ensure the MAC_Chunk is off-limits to the client, so
sewardjecf8e102003-07-12 12:11:39 +0000142 the mc->data field isn't visible to the leak checker. If memory
njn9a463242005-08-16 03:29:50 +0000143 management is working correctly, any pointer returned by VG_(malloc)
144 should be noaccess as far as the client is concerned. */
sewardjecf8e102003-07-12 12:11:39 +0000145 if (!MAC_(check_noaccess)( (Addr)mc, sizeof(MAC_Chunk), NULL )) {
njn5cc5d7e2005-08-11 02:09:25 +0000146 VG_(tool_panic)("create_MAC_Chunk: shadow area is accessible");
sewardjecf8e102003-07-12 12:11:39 +0000147 }
njn5cc5d7e2005-08-11 02:09:25 +0000148 return mc;
njn3e884182003-04-15 13:03:23 +0000149}
150
151/*------------------------------------------------------------*/
152/*--- client_malloc(), etc ---*/
153/*------------------------------------------------------------*/
154
nethercote7ac7f7b2004-11-02 12:36:02 +0000155static Bool complain_about_silly_args(SizeT sizeB, Char* fn)
156{
157 // Cast to a signed type to catch any unexpectedly negative args. We're
158 // assuming here that the size asked for is not greater than 2^31 bytes
159 // (for 32-bit platforms) or 2^63 bytes (for 64-bit platforms).
160 if ((SSizeT)sizeB < 0) {
161 VG_(message)(Vg_UserMsg, "Warning: silly arg (%d) to %s()", sizeB, fn );
162 return True;
163 }
164 return False;
165}
166
167static Bool complain_about_silly_args2(SizeT n, SizeT sizeB)
168{
169 if ((SSizeT)n < 0 || (SSizeT)sizeB < 0) {
170 VG_(message)(Vg_UserMsg, "Warning: silly args (%d,%d) to calloc()",
171 n, sizeB);
172 return True;
173 }
174 return False;
175}
176
njn3e884182003-04-15 13:03:23 +0000177/* Allocate memory and note change in memory available */
njn10785452003-05-20 16:38:24 +0000178__inline__
sewardj2a99cf62004-11-24 10:44:19 +0000179void* MAC_(new_block) ( ThreadId tid,
180 Addr p, SizeT size, SizeT align, UInt rzB,
nethercote57e36b32004-07-10 14:56:28 +0000181 Bool is_zeroed, MAC_AllocKind kind, VgHashTable table)
njn3e884182003-04-15 13:03:23 +0000182{
njn3e884182003-04-15 13:03:23 +0000183 VGP_PUSHCC(VgpCliMalloc);
njn3e884182003-04-15 13:03:23 +0000184 cmalloc_n_mallocs ++;
njn3e884182003-04-15 13:03:23 +0000185
nethercote57e36b32004-07-10 14:56:28 +0000186 // Allocate and zero if necessary
187 if (p) {
njnca82cc02004-11-22 17:18:48 +0000188 tl_assert(MAC_AllocCustom == kind);
nethercote57e36b32004-07-10 14:56:28 +0000189 } else {
njnca82cc02004-11-22 17:18:48 +0000190 tl_assert(MAC_AllocCustom != kind);
nethercote57e36b32004-07-10 14:56:28 +0000191 p = (Addr)VG_(cli_malloc)( align, size );
192 if (!p) {
193 VGP_POPCC(VgpCliMalloc);
194 return NULL;
195 }
196 if (is_zeroed) VG_(memset)((void*)p, 0, size);
197 }
198
njn2a513bf2005-06-30 02:34:32 +0000199 // Only update this stat if allocation succeeded.
200 cmalloc_bs_mallocd += size;
201
njn246a9d22005-08-14 06:24:20 +0000202 VG_(HT_add_node)( table, create_MAC_Chunk(tid, p, size, kind) );
njn3e884182003-04-15 13:03:23 +0000203
njn10785452003-05-20 16:38:24 +0000204 MAC_(ban_mem_heap)( p-rzB, rzB );
njn3e884182003-04-15 13:03:23 +0000205 MAC_(new_mem_heap)( p, size, is_zeroed );
njn10785452003-05-20 16:38:24 +0000206 MAC_(ban_mem_heap)( p+size, rzB );
njn3e884182003-04-15 13:03:23 +0000207
208 VGP_POPCC(VgpCliMalloc);
rjwalshbc0bb832004-06-19 18:12:36 +0000209
nethercote57e36b32004-07-10 14:56:28 +0000210 return (void*)p;
njn3e884182003-04-15 13:03:23 +0000211}
212
njn51d827b2005-05-09 01:02:08 +0000213void* MAC_(malloc) ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +0000214{
nethercote7ac7f7b2004-11-02 12:36:02 +0000215 if (complain_about_silly_args(n, "malloc")) {
njn3e884182003-04-15 13:03:23 +0000216 return NULL;
217 } else {
sewardj2a99cf62004-11-24 10:44:19 +0000218 return MAC_(new_block) ( tid, 0, n, VG_(clo_alignment),
njn51d827b2005-05-09 01:02:08 +0000219 MAC_MALLOC_REDZONE_SZB, /*is_zeroed*/False, MAC_AllocMalloc,
nethercote57e36b32004-07-10 14:56:28 +0000220 MAC_(malloc_list));
njn3e884182003-04-15 13:03:23 +0000221 }
222}
223
njn51d827b2005-05-09 01:02:08 +0000224void* MAC_(__builtin_new) ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +0000225{
nethercote7ac7f7b2004-11-02 12:36:02 +0000226 if (complain_about_silly_args(n, "__builtin_new")) {
njn3e884182003-04-15 13:03:23 +0000227 return NULL;
228 } else {
sewardj2a99cf62004-11-24 10:44:19 +0000229 return MAC_(new_block) ( tid, 0, n, VG_(clo_alignment),
njn51d827b2005-05-09 01:02:08 +0000230 MAC_MALLOC_REDZONE_SZB, /*is_zeroed*/False, MAC_AllocNew,
nethercote57e36b32004-07-10 14:56:28 +0000231 MAC_(malloc_list));
njn3e884182003-04-15 13:03:23 +0000232 }
233}
234
njn51d827b2005-05-09 01:02:08 +0000235void* MAC_(__builtin_vec_new) ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +0000236{
nethercote7ac7f7b2004-11-02 12:36:02 +0000237 if (complain_about_silly_args(n, "__builtin_vec_new")) {
njn3e884182003-04-15 13:03:23 +0000238 return NULL;
239 } else {
sewardj2a99cf62004-11-24 10:44:19 +0000240 return MAC_(new_block) ( tid, 0, n, VG_(clo_alignment),
njn51d827b2005-05-09 01:02:08 +0000241 MAC_MALLOC_REDZONE_SZB, /*is_zeroed*/False, MAC_AllocNewVec,
nethercote57e36b32004-07-10 14:56:28 +0000242 MAC_(malloc_list));
njn3e884182003-04-15 13:03:23 +0000243 }
244}
245
njn51d827b2005-05-09 01:02:08 +0000246void* MAC_(memalign) ( ThreadId tid, SizeT align, SizeT n )
njn3e884182003-04-15 13:03:23 +0000247{
nethercote7ac7f7b2004-11-02 12:36:02 +0000248 if (complain_about_silly_args(n, "memalign")) {
njn3e884182003-04-15 13:03:23 +0000249 return NULL;
250 } else {
sewardj2a99cf62004-11-24 10:44:19 +0000251 return MAC_(new_block) ( tid, 0, n, align,
njn51d827b2005-05-09 01:02:08 +0000252 MAC_MALLOC_REDZONE_SZB, /*is_zeroed*/False, MAC_AllocMalloc,
nethercote57e36b32004-07-10 14:56:28 +0000253 MAC_(malloc_list));
njn3e884182003-04-15 13:03:23 +0000254 }
255}
256
njn51d827b2005-05-09 01:02:08 +0000257void* MAC_(calloc) ( ThreadId tid, SizeT nmemb, SizeT size1 )
njn3e884182003-04-15 13:03:23 +0000258{
nethercote7ac7f7b2004-11-02 12:36:02 +0000259 if (complain_about_silly_args2(nmemb, size1)) {
njn3e884182003-04-15 13:03:23 +0000260 return NULL;
261 } else {
sewardj2a99cf62004-11-24 10:44:19 +0000262 return MAC_(new_block) ( tid, 0, nmemb*size1, VG_(clo_alignment),
njn51d827b2005-05-09 01:02:08 +0000263 MAC_MALLOC_REDZONE_SZB, /*is_zeroed*/True, MAC_AllocMalloc,
nethercote57e36b32004-07-10 14:56:28 +0000264 MAC_(malloc_list));
njn3e884182003-04-15 13:03:23 +0000265 }
266}
267
268static
njn34582fb2005-08-11 00:06:36 +0000269void die_and_free_mem ( ThreadId tid, MAC_Chunk* mc, SizeT rzB )
njn3e884182003-04-15 13:03:23 +0000270{
271 /* Note: ban redzones again -- just in case user de-banned them
272 with a client request... */
njn10785452003-05-20 16:38:24 +0000273 MAC_(ban_mem_heap)( mc->data-rzB, rzB );
njn3e884182003-04-15 13:03:23 +0000274 MAC_(die_mem_heap)( mc->data, mc->size );
njn10785452003-05-20 16:38:24 +0000275 MAC_(ban_mem_heap)( mc->data+mc->size, rzB );
njn3e884182003-04-15 13:03:23 +0000276
njn10785452003-05-20 16:38:24 +0000277 /* Put it out of harm's way for a while, if not from a client request */
rjwalshbc0bb832004-06-19 18:12:36 +0000278 if (MAC_AllocCustom != mc->allockind) {
279 /* Record where freed */
njnd01fef72005-03-25 23:35:48 +0000280 mc->where = VG_(record_ExeContext) ( tid );
njn10785452003-05-20 16:38:24 +0000281 add_to_freed_queue ( mc );
njn4bd67b52005-08-11 00:47:10 +0000282 } else {
njn10785452003-05-20 16:38:24 +0000283 VG_(free) ( mc );
njn4bd67b52005-08-11 00:47:10 +0000284 }
njn3e884182003-04-15 13:03:23 +0000285}
286
njn10785452003-05-20 16:38:24 +0000287__inline__
sewardj2a99cf62004-11-24 10:44:19 +0000288void MAC_(handle_free) ( ThreadId tid, Addr p, UInt rzB, MAC_AllocKind kind )
njn3e884182003-04-15 13:03:23 +0000289{
njn5cc5d7e2005-08-11 02:09:25 +0000290 MAC_Chunk* mc;
njn3e884182003-04-15 13:03:23 +0000291
292 VGP_PUSHCC(VgpCliMalloc);
293
294 cmalloc_n_frees++;
295
njn9a463242005-08-16 03:29:50 +0000296 mc = VG_(HT_remove) ( MAC_(malloc_list), (UWord)p );
njn3e884182003-04-15 13:03:23 +0000297 if (mc == NULL) {
njn72718642003-07-24 08:45:32 +0000298 MAC_(record_free_error) ( tid, p );
njn9a463242005-08-16 03:29:50 +0000299 } else {
njna0793652005-08-16 03:34:56 +0000300 /* check if it is a matching free() / delete / delete [] */
njn9a463242005-08-16 03:29:50 +0000301 if (kind != mc->allockind) {
302 MAC_(record_freemismatch_error) ( tid, p, mc );
303 }
304 die_and_free_mem ( tid, mc, rzB );
njn3e884182003-04-15 13:03:23 +0000305 }
306
njn3e884182003-04-15 13:03:23 +0000307 VGP_POPCC(VgpCliMalloc);
308}
309
njn51d827b2005-05-09 01:02:08 +0000310void MAC_(free) ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +0000311{
sewardj2a99cf62004-11-24 10:44:19 +0000312 MAC_(handle_free)(
njn51d827b2005-05-09 01:02:08 +0000313 tid, (Addr)p, MAC_MALLOC_REDZONE_SZB, MAC_AllocMalloc );
njn3e884182003-04-15 13:03:23 +0000314}
315
njn51d827b2005-05-09 01:02:08 +0000316void MAC_(__builtin_delete) ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +0000317{
sewardj2a99cf62004-11-24 10:44:19 +0000318 MAC_(handle_free)(
njn51d827b2005-05-09 01:02:08 +0000319 tid, (Addr)p, MAC_MALLOC_REDZONE_SZB, MAC_AllocNew);
njn3e884182003-04-15 13:03:23 +0000320}
321
njn51d827b2005-05-09 01:02:08 +0000322void MAC_(__builtin_vec_delete) ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +0000323{
sewardj2a99cf62004-11-24 10:44:19 +0000324 MAC_(handle_free)(
njn51d827b2005-05-09 01:02:08 +0000325 tid, (Addr)p, MAC_MALLOC_REDZONE_SZB, MAC_AllocNewVec);
njn3e884182003-04-15 13:03:23 +0000326}
327
njn5cc5d7e2005-08-11 02:09:25 +0000328void* MAC_(realloc) ( ThreadId tid, void* p_old, SizeT new_size )
njn3e884182003-04-15 13:03:23 +0000329{
njn5cc5d7e2005-08-11 02:09:25 +0000330 MAC_Chunk* mc;
331 void* p_new;
332 SizeT old_size;
njn3e884182003-04-15 13:03:23 +0000333
334 VGP_PUSHCC(VgpCliMalloc);
335
336 cmalloc_n_frees ++;
337 cmalloc_n_mallocs ++;
338 cmalloc_bs_mallocd += new_size;
339
nethercote7ac7f7b2004-11-02 12:36:02 +0000340 if (complain_about_silly_args(new_size, "realloc"))
njn3e884182003-04-15 13:03:23 +0000341 return NULL;
njn3e884182003-04-15 13:03:23 +0000342
njn5cc5d7e2005-08-11 02:09:25 +0000343 /* Remove the old block */
njn9a463242005-08-16 03:29:50 +0000344 mc = VG_(HT_remove) ( MAC_(malloc_list), (UWord)p_old );
njn3e884182003-04-15 13:03:23 +0000345 if (mc == NULL) {
njn5cc5d7e2005-08-11 02:09:25 +0000346 MAC_(record_free_error) ( tid, (Addr)p_old );
njn9a463242005-08-16 03:29:50 +0000347 /* We return to the program regardless. */
njn3e884182003-04-15 13:03:23 +0000348 VGP_POPCC(VgpCliMalloc);
349 return NULL;
350 }
njn5cc5d7e2005-08-11 02:09:25 +0000351
njn3e884182003-04-15 13:03:23 +0000352 /* check if its a matching free() / delete / delete [] */
353 if (MAC_AllocMalloc != mc->allockind) {
354 /* can not realloc a range that was allocated with new or new [] */
njn5cc5d7e2005-08-11 02:09:25 +0000355 MAC_(record_freemismatch_error) ( tid, (Addr)p_old, mc );
njn3e884182003-04-15 13:03:23 +0000356 /* but keep going anyway */
357 }
358
njn5cc5d7e2005-08-11 02:09:25 +0000359 old_size = mc->size;
360
361 if (old_size == new_size) {
njn3e884182003-04-15 13:03:23 +0000362 /* size unchanged */
njnd01fef72005-03-25 23:35:48 +0000363 mc->where = VG_(record_ExeContext)(tid);
njn5cc5d7e2005-08-11 02:09:25 +0000364 p_new = p_old;
njn3e884182003-04-15 13:03:23 +0000365
njn5cc5d7e2005-08-11 02:09:25 +0000366 } else if (old_size > new_size) {
njn3e884182003-04-15 13:03:23 +0000367 /* new size is smaller */
368 MAC_(die_mem_heap)( mc->data+new_size, mc->size-new_size );
369 mc->size = new_size;
njnd01fef72005-03-25 23:35:48 +0000370 mc->where = VG_(record_ExeContext)(tid);
njn5cc5d7e2005-08-11 02:09:25 +0000371 p_new = p_old;
njn3e884182003-04-15 13:03:23 +0000372
373 } else {
374 /* new size is bigger */
njn3e884182003-04-15 13:03:23 +0000375 /* Get new memory */
njn5cc5d7e2005-08-11 02:09:25 +0000376 Addr a_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size);
njn3e884182003-04-15 13:03:23 +0000377
njn5cc5d7e2005-08-11 02:09:25 +0000378 /* First half kept and copied, second half new, red zones as normal */
379 MAC_(ban_mem_heap) ( a_new-MAC_MALLOC_REDZONE_SZB, MAC_MALLOC_REDZONE_SZB );
380 MAC_(copy_mem_heap)( (Addr)p_old, a_new, mc->size );
381 MAC_(new_mem_heap) ( a_new+mc->size, new_size-mc->size, /*init'd*/False );
382 MAC_(ban_mem_heap) ( a_new+new_size, MAC_MALLOC_REDZONE_SZB );
njn3e884182003-04-15 13:03:23 +0000383
384 /* Copy from old to new */
njn5cc5d7e2005-08-11 02:09:25 +0000385 VG_(memcpy)((void*)a_new, p_old, mc->size);
njn3e884182003-04-15 13:03:23 +0000386
387 /* Free old memory */
njn5cc5d7e2005-08-11 02:09:25 +0000388 /* Nb: we have to allocate a new MAC_Chunk for the new memory rather
389 than recycling the old one, so that any erroneous accesses to the
390 old memory are reported. */
njn34582fb2005-08-11 00:06:36 +0000391 die_and_free_mem ( tid, mc, MAC_MALLOC_REDZONE_SZB );
njn3e884182003-04-15 13:03:23 +0000392
njn5cc5d7e2005-08-11 02:09:25 +0000393 // Allocate a new chunk.
394 mc = create_MAC_Chunk( tid, a_new, new_size, MAC_AllocMalloc );
395 p_new = (void*)a_new;
njn3e884182003-04-15 13:03:23 +0000396 }
njn5cc5d7e2005-08-11 02:09:25 +0000397
398 // Now insert the new mc (with a possibly new 'data' field) into
399 // malloc_list. If this realloc() did not increase the memory size, we
400 // will have removed and then re-added mc unnecessarily. But that's ok
401 // because shrinking a block with realloc() is (presumably) much rarer
402 // than growing it, and this way simplifies the growing case.
njn246a9d22005-08-14 06:24:20 +0000403 VG_(HT_add_node)( MAC_(malloc_list), mc );
njn5cc5d7e2005-08-11 02:09:25 +0000404
405 VGP_POPCC(VgpCliMalloc);
406 return p_new;
njn3e884182003-04-15 13:03:23 +0000407}
408
rjwalshbc0bb832004-06-19 18:12:36 +0000409/* Memory pool stuff. */
410
411void MAC_(create_mempool)(Addr pool, UInt rzB, Bool is_zeroed)
412{
njn9a463242005-08-16 03:29:50 +0000413 MAC_Mempool* mp = VG_(malloc)(sizeof(MAC_Mempool));
414 mp->pool = pool;
415 mp->rzB = rzB;
416 mp->is_zeroed = is_zeroed;
417 mp->chunks = VG_(HT_construct)( 3001 ); // prime, not so big
rjwalshbc0bb832004-06-19 18:12:36 +0000418
419 /* Paranoia ... ensure this area is off-limits to the client, so
420 the mp->data field isn't visible to the leak checker. If memory
421 management is working correctly, anything pointer returned by
422 VG_(malloc) should be noaccess as far as the client is
423 concerned. */
424 if (!MAC_(check_noaccess)( (Addr)mp, sizeof(MAC_Mempool), NULL )) {
njn67993252004-11-22 18:02:32 +0000425 VG_(tool_panic)("MAC_(create_mempool): shadow area is accessible");
rjwalshbc0bb832004-06-19 18:12:36 +0000426 }
427
njn246a9d22005-08-14 06:24:20 +0000428 VG_(HT_add_node)( MAC_(mempool_list), mp );
rjwalshbc0bb832004-06-19 18:12:36 +0000429}
430
431void MAC_(destroy_mempool)(Addr pool)
432{
njn1d0cb0d2005-08-15 01:52:02 +0000433 MAC_Chunk* mc;
thughes4ad52d02004-06-27 17:37:21 +0000434 MAC_Mempool* mp;
rjwalshbc0bb832004-06-19 18:12:36 +0000435
njn12627272005-08-14 18:32:16 +0000436 mp = VG_(HT_remove) ( MAC_(mempool_list), (UWord)pool );
rjwalshbc0bb832004-06-19 18:12:36 +0000437
438 if (mp == NULL) {
sewardj76754cf2005-03-14 00:14:04 +0000439 ThreadId tid = VG_(get_running_tid)();
rjwalshbc0bb832004-06-19 18:12:36 +0000440 MAC_(record_illegal_mempool_error) ( tid, pool );
441 return;
442 }
443
njn1d0cb0d2005-08-15 01:52:02 +0000444 // Clean up the chunks, one by one
445 VG_(HT_ResetIter)(mp->chunks);
446 while ( (mc = VG_(HT_Next)(mp->chunks)) ) {
447 /* Note: ban redzones again -- just in case user de-banned them
448 with a client request... */
449 MAC_(ban_mem_heap)(mc->data-mp->rzB, mp->rzB );
450 MAC_(die_mem_heap)(mc->data, mc->size );
451 MAC_(ban_mem_heap)(mc->data+mc->size, mp->rzB );
452 }
453 // Destroy the chunk table
rjwalshbc0bb832004-06-19 18:12:36 +0000454 VG_(HT_destruct)(mp->chunks);
455
456 VG_(free)(mp);
457}
458
sewardj2a99cf62004-11-24 10:44:19 +0000459void MAC_(mempool_alloc)(ThreadId tid, Addr pool, Addr addr, SizeT size)
rjwalshbc0bb832004-06-19 18:12:36 +0000460{
njn9a463242005-08-16 03:29:50 +0000461 MAC_Mempool* mp = VG_(HT_lookup) ( MAC_(mempool_list), (UWord)pool );
rjwalshbc0bb832004-06-19 18:12:36 +0000462
463 if (mp == NULL) {
rjwalshbc0bb832004-06-19 18:12:36 +0000464 MAC_(record_illegal_mempool_error) ( tid, pool );
njn9a463242005-08-16 03:29:50 +0000465 } else {
466 MAC_(new_block)(tid, addr, size, /*ignored*/0, mp->rzB, mp->is_zeroed,
467 MAC_AllocCustom, mp->chunks);
rjwalshbc0bb832004-06-19 18:12:36 +0000468 }
rjwalshbc0bb832004-06-19 18:12:36 +0000469}
470
471void MAC_(mempool_free)(Addr pool, Addr addr)
472{
473 MAC_Mempool* mp;
rjwalshbc0bb832004-06-19 18:12:36 +0000474 MAC_Chunk* mc;
sewardj76754cf2005-03-14 00:14:04 +0000475 ThreadId tid = VG_(get_running_tid)();
rjwalshbc0bb832004-06-19 18:12:36 +0000476
njn12627272005-08-14 18:32:16 +0000477 mp = VG_(HT_lookup)(MAC_(mempool_list), (UWord)pool);
rjwalshbc0bb832004-06-19 18:12:36 +0000478 if (mp == NULL) {
479 MAC_(record_illegal_mempool_error)(tid, pool);
480 return;
481 }
482
njn9a463242005-08-16 03:29:50 +0000483 mc = VG_(HT_remove)(mp->chunks, (UWord)addr);
rjwalshbc0bb832004-06-19 18:12:36 +0000484 if (mc == NULL) {
485 MAC_(record_free_error)(tid, (Addr)addr);
486 return;
487 }
488
njn34582fb2005-08-11 00:06:36 +0000489 die_and_free_mem ( tid, mc, mp->rzB );
rjwalshbc0bb832004-06-19 18:12:36 +0000490}
491
njn86f12dc2005-03-14 01:16:05 +0000492/*------------------------------------------------------------*/
493/*--- Statistics printing ---*/
494/*------------------------------------------------------------*/
495
njn86f12dc2005-03-14 01:16:05 +0000496void MAC_(print_malloc_stats) ( void )
497{
njn1d0cb0d2005-08-15 01:52:02 +0000498 MAC_Chunk* mc;
499 UInt nblocks = 0;
500 SizeT nbytes = 0;
njn86f12dc2005-03-14 01:16:05 +0000501
502 if (VG_(clo_verbosity) == 0)
503 return;
sewardj71bc3cb2005-05-19 00:25:45 +0000504 if (VG_(clo_xml))
505 return;
njn86f12dc2005-03-14 01:16:05 +0000506
507 /* Count memory still in use. */
njn1d0cb0d2005-08-15 01:52:02 +0000508 VG_(HT_ResetIter)(MAC_(malloc_list));
509 while ( (mc = VG_(HT_Next)(MAC_(malloc_list))) ) {
510 nblocks++;
511 nbytes += mc->size;
512 }
njn86f12dc2005-03-14 01:16:05 +0000513
514 VG_(message)(Vg_UserMsg,
515 "malloc/free: in use at exit: %d bytes in %d blocks.",
njn1d0cb0d2005-08-15 01:52:02 +0000516 nbytes, nblocks);
njn86f12dc2005-03-14 01:16:05 +0000517 VG_(message)(Vg_UserMsg,
518 "malloc/free: %d allocs, %d frees, %u bytes allocated.",
519 cmalloc_n_mallocs,
520 cmalloc_n_frees, cmalloc_bs_mallocd);
521 if (VG_(clo_verbosity) > 1)
522 VG_(message)(Vg_UserMsg, "");
523}
524
njn3e884182003-04-15 13:03:23 +0000525/*--------------------------------------------------------------------*/
njn86f12dc2005-03-14 01:16:05 +0000526/*--- end ---*/
njn3e884182003-04-15 13:03:23 +0000527/*--------------------------------------------------------------------*/