blob: 523dcf082d65e181c9119c6d324733b60fd13aea [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"
njnc7561b92005-06-19 01:24:32 +000042#include "pub_tool_replacemalloc.h"
43#include "pub_tool_threadstate.h"
44#include "mac_shared.h"
njn3e884182003-04-15 13:03:23 +000045
46/*------------------------------------------------------------*/
47/*--- Defns ---*/
48/*------------------------------------------------------------*/
49
50/* Stats ... */
nethercote7ac7f7b2004-11-02 12:36:02 +000051static SizeT cmalloc_n_mallocs = 0;
52static SizeT cmalloc_n_frees = 0;
53static SizeT cmalloc_bs_mallocd = 0;
njn3e884182003-04-15 13:03:23 +000054
nethercote7cc9c232004-01-21 15:08:04 +000055/* Function pointers for the two tools to track interesting events. */
nethercote451eae92004-11-02 13:06:32 +000056void (*MAC_(new_mem_heap)) ( Addr a, SizeT len, Bool is_inited ) = NULL;
57void (*MAC_(ban_mem_heap)) ( Addr a, SizeT len ) = NULL;
58void (*MAC_(die_mem_heap)) ( Addr a, SizeT len ) = NULL;
59void (*MAC_(copy_mem_heap))( Addr from, Addr to, SizeT len ) = NULL;
sewardjecf8e102003-07-12 12:11:39 +000060
61/* Function pointers for internal sanity checking. */
nethercote451eae92004-11-02 13:06:32 +000062Bool (*MAC_(check_noaccess))( Addr a, SizeT len, Addr* bad_addr ) = NULL;
sewardjf9025f72003-07-12 01:41:24 +000063
64
njn3e884182003-04-15 13:03:23 +000065/*------------------------------------------------------------*/
66/*--- Tracking malloc'd and free'd blocks ---*/
67/*------------------------------------------------------------*/
68
njn9a463242005-08-16 03:29:50 +000069/* Record malloc'd blocks. */
njn3e884182003-04-15 13:03:23 +000070VgHashTable MAC_(malloc_list) = NULL;
rjwalshbc0bb832004-06-19 18:12:36 +000071
njn9a463242005-08-16 03:29:50 +000072/* Memory pools. */
rjwalshbc0bb832004-06-19 18:12:36 +000073VgHashTable MAC_(mempool_list) = NULL;
njn3e884182003-04-15 13:03:23 +000074
75/* Records blocks after freeing. */
76static MAC_Chunk* freed_list_start = NULL;
77static MAC_Chunk* freed_list_end = NULL;
78static Int freed_list_volume = 0;
79
80/* Put a shadow chunk on the freed blocks queue, possibly freeing up
81 some of the oldest blocks in the queue at the same time. */
82static void add_to_freed_queue ( MAC_Chunk* mc )
83{
njn3e884182003-04-15 13:03:23 +000084 /* Put it at the end of the freed list */
85 if (freed_list_end == NULL) {
njnca82cc02004-11-22 17:18:48 +000086 tl_assert(freed_list_start == NULL);
njn3e884182003-04-15 13:03:23 +000087 freed_list_end = freed_list_start = mc;
88 freed_list_volume = mc->size;
89 } else {
njnca82cc02004-11-22 17:18:48 +000090 tl_assert(freed_list_end->next == NULL);
njn3e884182003-04-15 13:03:23 +000091 freed_list_end->next = mc;
92 freed_list_end = mc;
93 freed_list_volume += mc->size;
94 }
95 mc->next = NULL;
96
97 /* Release enough of the oldest blocks to bring the free queue
98 volume below vg_clo_freelist_vol. */
99
100 while (freed_list_volume > MAC_(clo_freelist_vol)) {
njn9a463242005-08-16 03:29:50 +0000101 MAC_Chunk* mc1;
102
njnca82cc02004-11-22 17:18:48 +0000103 tl_assert(freed_list_start != NULL);
104 tl_assert(freed_list_end != NULL);
njn3e884182003-04-15 13:03:23 +0000105
njn5cc5d7e2005-08-11 02:09:25 +0000106 mc1 = freed_list_start;
107 freed_list_volume -= mc1->size;
njn3e884182003-04-15 13:03:23 +0000108 /* VG_(printf)("volume now %d\n", freed_list_volume); */
njnca82cc02004-11-22 17:18:48 +0000109 tl_assert(freed_list_volume >= 0);
njn3e884182003-04-15 13:03:23 +0000110
111 if (freed_list_start == freed_list_end) {
112 freed_list_start = freed_list_end = NULL;
113 } else {
njn5cc5d7e2005-08-11 02:09:25 +0000114 freed_list_start = mc1->next;
njn3e884182003-04-15 13:03:23 +0000115 }
njn5cc5d7e2005-08-11 02:09:25 +0000116 mc1->next = NULL; /* just paranoia */
njn3e884182003-04-15 13:03:23 +0000117
118 /* free MAC_Chunk */
njn5cc5d7e2005-08-11 02:09:25 +0000119 VG_(cli_free) ( (void*)(mc1->data) );
120 VG_(free) ( mc1 );
njn3e884182003-04-15 13:03:23 +0000121 }
122}
123
njn1d0cb0d2005-08-15 01:52:02 +0000124MAC_Chunk* MAC_(get_freed_list_head)(void)
njn3e884182003-04-15 13:03:23 +0000125{
njn1d0cb0d2005-08-15 01:52:02 +0000126 return freed_list_start;
njn3e884182003-04-15 13:03:23 +0000127}
128
njn10785452003-05-20 16:38:24 +0000129/* Allocate its shadow chunk, put it on the appropriate list. */
130static
njn5cc5d7e2005-08-11 02:09:25 +0000131MAC_Chunk* create_MAC_Chunk ( ThreadId tid, Addr p, SizeT size,
132 MAC_AllocKind kind)
njn3e884182003-04-15 13:03:23 +0000133{
njn5cc5d7e2005-08-11 02:09:25 +0000134 MAC_Chunk* mc = VG_(malloc)(sizeof(MAC_Chunk));
njn3e884182003-04-15 13:03:23 +0000135 mc->data = p;
136 mc->size = size;
137 mc->allockind = kind;
njnd01fef72005-03-25 23:35:48 +0000138 mc->where = VG_(record_ExeContext)(tid);
njn3e884182003-04-15 13:03:23 +0000139
njn9a463242005-08-16 03:29:50 +0000140 /* Paranoia ... ensure the MAC_Chunk is off-limits to the client, so
sewardjecf8e102003-07-12 12:11:39 +0000141 the mc->data field isn't visible to the leak checker. If memory
njn9a463242005-08-16 03:29:50 +0000142 management is working correctly, any pointer returned by VG_(malloc)
143 should be noaccess as far as the client is concerned. */
sewardjecf8e102003-07-12 12:11:39 +0000144 if (!MAC_(check_noaccess)( (Addr)mc, sizeof(MAC_Chunk), NULL )) {
njn5cc5d7e2005-08-11 02:09:25 +0000145 VG_(tool_panic)("create_MAC_Chunk: shadow area is accessible");
sewardjecf8e102003-07-12 12:11:39 +0000146 }
njn5cc5d7e2005-08-11 02:09:25 +0000147 return mc;
njn3e884182003-04-15 13:03:23 +0000148}
149
150/*------------------------------------------------------------*/
151/*--- client_malloc(), etc ---*/
152/*------------------------------------------------------------*/
153
nethercote7ac7f7b2004-11-02 12:36:02 +0000154static Bool complain_about_silly_args(SizeT sizeB, Char* fn)
155{
156 // Cast to a signed type to catch any unexpectedly negative args. We're
157 // assuming here that the size asked for is not greater than 2^31 bytes
158 // (for 32-bit platforms) or 2^63 bytes (for 64-bit platforms).
159 if ((SSizeT)sizeB < 0) {
tomc1bcf102005-10-13 15:29:39 +0000160 VG_(message)(Vg_UserMsg, "Warning: silly arg (%ld) to %s()",
161 (SSizeT)sizeB, fn );
nethercote7ac7f7b2004-11-02 12:36:02 +0000162 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) {
tomc1bcf102005-10-13 15:29:39 +0000170 VG_(message)(Vg_UserMsg, "Warning: silly args (%ld,%ld) to calloc()",
171 (SSizeT)n, (SSizeT)sizeB);
nethercote7ac7f7b2004-11-02 12:36:02 +0000172 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 cmalloc_n_mallocs ++;
njn3e884182003-04-15 13:03:23 +0000184
nethercote57e36b32004-07-10 14:56:28 +0000185 // Allocate and zero if necessary
186 if (p) {
njnca82cc02004-11-22 17:18:48 +0000187 tl_assert(MAC_AllocCustom == kind);
nethercote57e36b32004-07-10 14:56:28 +0000188 } else {
njnca82cc02004-11-22 17:18:48 +0000189 tl_assert(MAC_AllocCustom != kind);
nethercote57e36b32004-07-10 14:56:28 +0000190 p = (Addr)VG_(cli_malloc)( align, size );
191 if (!p) {
nethercote57e36b32004-07-10 14:56:28 +0000192 return NULL;
193 }
194 if (is_zeroed) VG_(memset)((void*)p, 0, size);
195 }
196
njn2a513bf2005-06-30 02:34:32 +0000197 // Only update this stat if allocation succeeded.
198 cmalloc_bs_mallocd += size;
199
njn246a9d22005-08-14 06:24:20 +0000200 VG_(HT_add_node)( table, create_MAC_Chunk(tid, p, size, kind) );
njn3e884182003-04-15 13:03:23 +0000201
njn10785452003-05-20 16:38:24 +0000202 MAC_(ban_mem_heap)( p-rzB, rzB );
njn3e884182003-04-15 13:03:23 +0000203 MAC_(new_mem_heap)( p, size, is_zeroed );
njn10785452003-05-20 16:38:24 +0000204 MAC_(ban_mem_heap)( p+size, rzB );
njn3e884182003-04-15 13:03:23 +0000205
nethercote57e36b32004-07-10 14:56:28 +0000206 return (void*)p;
njn3e884182003-04-15 13:03:23 +0000207}
208
njn51d827b2005-05-09 01:02:08 +0000209void* MAC_(malloc) ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +0000210{
nethercote7ac7f7b2004-11-02 12:36:02 +0000211 if (complain_about_silly_args(n, "malloc")) {
njn3e884182003-04-15 13:03:23 +0000212 return NULL;
213 } else {
sewardj2a99cf62004-11-24 10:44:19 +0000214 return MAC_(new_block) ( tid, 0, n, VG_(clo_alignment),
njn51d827b2005-05-09 01:02:08 +0000215 MAC_MALLOC_REDZONE_SZB, /*is_zeroed*/False, MAC_AllocMalloc,
nethercote57e36b32004-07-10 14:56:28 +0000216 MAC_(malloc_list));
njn3e884182003-04-15 13:03:23 +0000217 }
218}
219
njn51d827b2005-05-09 01:02:08 +0000220void* MAC_(__builtin_new) ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +0000221{
nethercote7ac7f7b2004-11-02 12:36:02 +0000222 if (complain_about_silly_args(n, "__builtin_new")) {
njn3e884182003-04-15 13:03:23 +0000223 return NULL;
224 } else {
sewardj2a99cf62004-11-24 10:44:19 +0000225 return MAC_(new_block) ( tid, 0, n, VG_(clo_alignment),
njn51d827b2005-05-09 01:02:08 +0000226 MAC_MALLOC_REDZONE_SZB, /*is_zeroed*/False, MAC_AllocNew,
nethercote57e36b32004-07-10 14:56:28 +0000227 MAC_(malloc_list));
njn3e884182003-04-15 13:03:23 +0000228 }
229}
230
njn51d827b2005-05-09 01:02:08 +0000231void* MAC_(__builtin_vec_new) ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +0000232{
nethercote7ac7f7b2004-11-02 12:36:02 +0000233 if (complain_about_silly_args(n, "__builtin_vec_new")) {
njn3e884182003-04-15 13:03:23 +0000234 return NULL;
235 } else {
sewardj2a99cf62004-11-24 10:44:19 +0000236 return MAC_(new_block) ( tid, 0, n, VG_(clo_alignment),
njn51d827b2005-05-09 01:02:08 +0000237 MAC_MALLOC_REDZONE_SZB, /*is_zeroed*/False, MAC_AllocNewVec,
nethercote57e36b32004-07-10 14:56:28 +0000238 MAC_(malloc_list));
njn3e884182003-04-15 13:03:23 +0000239 }
240}
241
njn51d827b2005-05-09 01:02:08 +0000242void* MAC_(memalign) ( ThreadId tid, SizeT align, SizeT n )
njn3e884182003-04-15 13:03:23 +0000243{
nethercote7ac7f7b2004-11-02 12:36:02 +0000244 if (complain_about_silly_args(n, "memalign")) {
njn3e884182003-04-15 13:03:23 +0000245 return NULL;
246 } else {
sewardj2a99cf62004-11-24 10:44:19 +0000247 return MAC_(new_block) ( tid, 0, n, align,
njn51d827b2005-05-09 01:02:08 +0000248 MAC_MALLOC_REDZONE_SZB, /*is_zeroed*/False, MAC_AllocMalloc,
nethercote57e36b32004-07-10 14:56:28 +0000249 MAC_(malloc_list));
njn3e884182003-04-15 13:03:23 +0000250 }
251}
252
njn51d827b2005-05-09 01:02:08 +0000253void* MAC_(calloc) ( ThreadId tid, SizeT nmemb, SizeT size1 )
njn3e884182003-04-15 13:03:23 +0000254{
nethercote7ac7f7b2004-11-02 12:36:02 +0000255 if (complain_about_silly_args2(nmemb, size1)) {
njn3e884182003-04-15 13:03:23 +0000256 return NULL;
257 } else {
sewardj2a99cf62004-11-24 10:44:19 +0000258 return MAC_(new_block) ( tid, 0, nmemb*size1, VG_(clo_alignment),
njn51d827b2005-05-09 01:02:08 +0000259 MAC_MALLOC_REDZONE_SZB, /*is_zeroed*/True, MAC_AllocMalloc,
nethercote57e36b32004-07-10 14:56:28 +0000260 MAC_(malloc_list));
njn3e884182003-04-15 13:03:23 +0000261 }
262}
263
264static
njn34582fb2005-08-11 00:06:36 +0000265void die_and_free_mem ( ThreadId tid, MAC_Chunk* mc, SizeT rzB )
njn3e884182003-04-15 13:03:23 +0000266{
267 /* Note: ban redzones again -- just in case user de-banned them
268 with a client request... */
njn10785452003-05-20 16:38:24 +0000269 MAC_(ban_mem_heap)( mc->data-rzB, rzB );
njn3e884182003-04-15 13:03:23 +0000270 MAC_(die_mem_heap)( mc->data, mc->size );
njn10785452003-05-20 16:38:24 +0000271 MAC_(ban_mem_heap)( mc->data+mc->size, rzB );
njn3e884182003-04-15 13:03:23 +0000272
njn10785452003-05-20 16:38:24 +0000273 /* Put it out of harm's way for a while, if not from a client request */
rjwalshbc0bb832004-06-19 18:12:36 +0000274 if (MAC_AllocCustom != mc->allockind) {
275 /* Record where freed */
njnd01fef72005-03-25 23:35:48 +0000276 mc->where = VG_(record_ExeContext) ( tid );
njn10785452003-05-20 16:38:24 +0000277 add_to_freed_queue ( mc );
njn4bd67b52005-08-11 00:47:10 +0000278 } else {
njn10785452003-05-20 16:38:24 +0000279 VG_(free) ( mc );
njn4bd67b52005-08-11 00:47:10 +0000280 }
njn3e884182003-04-15 13:03:23 +0000281}
282
njn10785452003-05-20 16:38:24 +0000283__inline__
sewardj2a99cf62004-11-24 10:44:19 +0000284void MAC_(handle_free) ( ThreadId tid, Addr p, UInt rzB, MAC_AllocKind kind )
njn3e884182003-04-15 13:03:23 +0000285{
njn5cc5d7e2005-08-11 02:09:25 +0000286 MAC_Chunk* mc;
njn3e884182003-04-15 13:03:23 +0000287
njn3e884182003-04-15 13:03:23 +0000288 cmalloc_n_frees++;
289
njn9a463242005-08-16 03:29:50 +0000290 mc = VG_(HT_remove) ( MAC_(malloc_list), (UWord)p );
njn3e884182003-04-15 13:03:23 +0000291 if (mc == NULL) {
njn72718642003-07-24 08:45:32 +0000292 MAC_(record_free_error) ( tid, p );
njn9a463242005-08-16 03:29:50 +0000293 } else {
njna0793652005-08-16 03:34:56 +0000294 /* check if it is a matching free() / delete / delete [] */
njn9a463242005-08-16 03:29:50 +0000295 if (kind != mc->allockind) {
296 MAC_(record_freemismatch_error) ( tid, p, mc );
297 }
298 die_and_free_mem ( tid, mc, rzB );
njn3e884182003-04-15 13:03:23 +0000299 }
njn3e884182003-04-15 13:03:23 +0000300}
301
njn51d827b2005-05-09 01:02:08 +0000302void MAC_(free) ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +0000303{
sewardj2a99cf62004-11-24 10:44:19 +0000304 MAC_(handle_free)(
njn51d827b2005-05-09 01:02:08 +0000305 tid, (Addr)p, MAC_MALLOC_REDZONE_SZB, MAC_AllocMalloc );
njn3e884182003-04-15 13:03:23 +0000306}
307
njn51d827b2005-05-09 01:02:08 +0000308void MAC_(__builtin_delete) ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +0000309{
sewardj2a99cf62004-11-24 10:44:19 +0000310 MAC_(handle_free)(
njn51d827b2005-05-09 01:02:08 +0000311 tid, (Addr)p, MAC_MALLOC_REDZONE_SZB, MAC_AllocNew);
njn3e884182003-04-15 13:03:23 +0000312}
313
njn51d827b2005-05-09 01:02:08 +0000314void MAC_(__builtin_vec_delete) ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +0000315{
sewardj2a99cf62004-11-24 10:44:19 +0000316 MAC_(handle_free)(
njn51d827b2005-05-09 01:02:08 +0000317 tid, (Addr)p, MAC_MALLOC_REDZONE_SZB, MAC_AllocNewVec);
njn3e884182003-04-15 13:03:23 +0000318}
319
njn5cc5d7e2005-08-11 02:09:25 +0000320void* MAC_(realloc) ( ThreadId tid, void* p_old, SizeT new_size )
njn3e884182003-04-15 13:03:23 +0000321{
njn5cc5d7e2005-08-11 02:09:25 +0000322 MAC_Chunk* mc;
323 void* p_new;
324 SizeT old_size;
njn3e884182003-04-15 13:03:23 +0000325
njn3e884182003-04-15 13:03:23 +0000326 cmalloc_n_frees ++;
327 cmalloc_n_mallocs ++;
328 cmalloc_bs_mallocd += new_size;
329
nethercote7ac7f7b2004-11-02 12:36:02 +0000330 if (complain_about_silly_args(new_size, "realloc"))
njn3e884182003-04-15 13:03:23 +0000331 return NULL;
njn3e884182003-04-15 13:03:23 +0000332
njn5cc5d7e2005-08-11 02:09:25 +0000333 /* Remove the old block */
njn9a463242005-08-16 03:29:50 +0000334 mc = VG_(HT_remove) ( MAC_(malloc_list), (UWord)p_old );
njn3e884182003-04-15 13:03:23 +0000335 if (mc == NULL) {
njn5cc5d7e2005-08-11 02:09:25 +0000336 MAC_(record_free_error) ( tid, (Addr)p_old );
njn9a463242005-08-16 03:29:50 +0000337 /* We return to the program regardless. */
njn3e884182003-04-15 13:03:23 +0000338 return NULL;
339 }
njn5cc5d7e2005-08-11 02:09:25 +0000340
njn3e884182003-04-15 13:03:23 +0000341 /* check if its a matching free() / delete / delete [] */
342 if (MAC_AllocMalloc != mc->allockind) {
343 /* can not realloc a range that was allocated with new or new [] */
njn5cc5d7e2005-08-11 02:09:25 +0000344 MAC_(record_freemismatch_error) ( tid, (Addr)p_old, mc );
njn3e884182003-04-15 13:03:23 +0000345 /* but keep going anyway */
346 }
347
njn5cc5d7e2005-08-11 02:09:25 +0000348 old_size = mc->size;
349
350 if (old_size == new_size) {
njn3e884182003-04-15 13:03:23 +0000351 /* size unchanged */
njnd01fef72005-03-25 23:35:48 +0000352 mc->where = VG_(record_ExeContext)(tid);
njn5cc5d7e2005-08-11 02:09:25 +0000353 p_new = p_old;
njn3e884182003-04-15 13:03:23 +0000354
njn5cc5d7e2005-08-11 02:09:25 +0000355 } else if (old_size > new_size) {
njn3e884182003-04-15 13:03:23 +0000356 /* new size is smaller */
357 MAC_(die_mem_heap)( mc->data+new_size, mc->size-new_size );
358 mc->size = new_size;
njnd01fef72005-03-25 23:35:48 +0000359 mc->where = VG_(record_ExeContext)(tid);
njn5cc5d7e2005-08-11 02:09:25 +0000360 p_new = p_old;
njn3e884182003-04-15 13:03:23 +0000361
362 } else {
363 /* new size is bigger */
njn3e884182003-04-15 13:03:23 +0000364 /* Get new memory */
njn5cc5d7e2005-08-11 02:09:25 +0000365 Addr a_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size);
njn3e884182003-04-15 13:03:23 +0000366
tom0cd42f02005-10-06 09:00:17 +0000367 if (a_new) {
368 /* First half kept and copied, second half new, red zones as normal */
369 MAC_(ban_mem_heap) ( a_new-MAC_MALLOC_REDZONE_SZB, MAC_MALLOC_REDZONE_SZB );
370 MAC_(copy_mem_heap)( (Addr)p_old, a_new, mc->size );
371 MAC_(new_mem_heap) ( a_new+mc->size, new_size-mc->size, /*init'd*/False );
372 MAC_(ban_mem_heap) ( a_new+new_size, MAC_MALLOC_REDZONE_SZB );
njn3e884182003-04-15 13:03:23 +0000373
tom0cd42f02005-10-06 09:00:17 +0000374 /* Copy from old to new */
375 VG_(memcpy)((void*)a_new, p_old, mc->size);
njn3e884182003-04-15 13:03:23 +0000376
tom0cd42f02005-10-06 09:00:17 +0000377 /* Free old memory */
378 /* Nb: we have to allocate a new MAC_Chunk for the new memory rather
379 than recycling the old one, so that any erroneous accesses to the
380 old memory are reported. */
381 die_and_free_mem ( tid, mc, MAC_MALLOC_REDZONE_SZB );
njn3e884182003-04-15 13:03:23 +0000382
tom0cd42f02005-10-06 09:00:17 +0000383 // Allocate a new chunk.
384 mc = create_MAC_Chunk( tid, a_new, new_size, MAC_AllocMalloc );
385 }
386
njn5cc5d7e2005-08-11 02:09:25 +0000387 p_new = (void*)a_new;
njn3e884182003-04-15 13:03:23 +0000388 }
njn5cc5d7e2005-08-11 02:09:25 +0000389
390 // Now insert the new mc (with a possibly new 'data' field) into
391 // malloc_list. If this realloc() did not increase the memory size, we
392 // will have removed and then re-added mc unnecessarily. But that's ok
393 // because shrinking a block with realloc() is (presumably) much rarer
394 // than growing it, and this way simplifies the growing case.
njn246a9d22005-08-14 06:24:20 +0000395 VG_(HT_add_node)( MAC_(malloc_list), mc );
njn5cc5d7e2005-08-11 02:09:25 +0000396
njn5cc5d7e2005-08-11 02:09:25 +0000397 return p_new;
njn3e884182003-04-15 13:03:23 +0000398}
399
rjwalshbc0bb832004-06-19 18:12:36 +0000400/* Memory pool stuff. */
401
402void MAC_(create_mempool)(Addr pool, UInt rzB, Bool is_zeroed)
403{
njn9a463242005-08-16 03:29:50 +0000404 MAC_Mempool* mp = VG_(malloc)(sizeof(MAC_Mempool));
405 mp->pool = pool;
406 mp->rzB = rzB;
407 mp->is_zeroed = is_zeroed;
408 mp->chunks = VG_(HT_construct)( 3001 ); // prime, not so big
rjwalshbc0bb832004-06-19 18:12:36 +0000409
410 /* Paranoia ... ensure this area is off-limits to the client, so
411 the mp->data field isn't visible to the leak checker. If memory
412 management is working correctly, anything pointer returned by
413 VG_(malloc) should be noaccess as far as the client is
414 concerned. */
415 if (!MAC_(check_noaccess)( (Addr)mp, sizeof(MAC_Mempool), NULL )) {
njn67993252004-11-22 18:02:32 +0000416 VG_(tool_panic)("MAC_(create_mempool): shadow area is accessible");
rjwalshbc0bb832004-06-19 18:12:36 +0000417 }
418
njn246a9d22005-08-14 06:24:20 +0000419 VG_(HT_add_node)( MAC_(mempool_list), mp );
rjwalshbc0bb832004-06-19 18:12:36 +0000420}
421
422void MAC_(destroy_mempool)(Addr pool)
423{
njn1d0cb0d2005-08-15 01:52:02 +0000424 MAC_Chunk* mc;
thughes4ad52d02004-06-27 17:37:21 +0000425 MAC_Mempool* mp;
rjwalshbc0bb832004-06-19 18:12:36 +0000426
njn12627272005-08-14 18:32:16 +0000427 mp = VG_(HT_remove) ( MAC_(mempool_list), (UWord)pool );
rjwalshbc0bb832004-06-19 18:12:36 +0000428
429 if (mp == NULL) {
sewardj76754cf2005-03-14 00:14:04 +0000430 ThreadId tid = VG_(get_running_tid)();
rjwalshbc0bb832004-06-19 18:12:36 +0000431 MAC_(record_illegal_mempool_error) ( tid, pool );
432 return;
433 }
434
njn1d0cb0d2005-08-15 01:52:02 +0000435 // Clean up the chunks, one by one
436 VG_(HT_ResetIter)(mp->chunks);
437 while ( (mc = VG_(HT_Next)(mp->chunks)) ) {
438 /* Note: ban redzones again -- just in case user de-banned them
439 with a client request... */
440 MAC_(ban_mem_heap)(mc->data-mp->rzB, mp->rzB );
441 MAC_(die_mem_heap)(mc->data, mc->size );
442 MAC_(ban_mem_heap)(mc->data+mc->size, mp->rzB );
443 }
444 // Destroy the chunk table
rjwalshbc0bb832004-06-19 18:12:36 +0000445 VG_(HT_destruct)(mp->chunks);
446
447 VG_(free)(mp);
448}
449
sewardj2a99cf62004-11-24 10:44:19 +0000450void MAC_(mempool_alloc)(ThreadId tid, Addr pool, Addr addr, SizeT size)
rjwalshbc0bb832004-06-19 18:12:36 +0000451{
njn9a463242005-08-16 03:29:50 +0000452 MAC_Mempool* mp = VG_(HT_lookup) ( MAC_(mempool_list), (UWord)pool );
rjwalshbc0bb832004-06-19 18:12:36 +0000453
454 if (mp == NULL) {
rjwalshbc0bb832004-06-19 18:12:36 +0000455 MAC_(record_illegal_mempool_error) ( tid, pool );
njn9a463242005-08-16 03:29:50 +0000456 } else {
457 MAC_(new_block)(tid, addr, size, /*ignored*/0, mp->rzB, mp->is_zeroed,
458 MAC_AllocCustom, mp->chunks);
rjwalshbc0bb832004-06-19 18:12:36 +0000459 }
rjwalshbc0bb832004-06-19 18:12:36 +0000460}
461
462void MAC_(mempool_free)(Addr pool, Addr addr)
463{
464 MAC_Mempool* mp;
rjwalshbc0bb832004-06-19 18:12:36 +0000465 MAC_Chunk* mc;
sewardj76754cf2005-03-14 00:14:04 +0000466 ThreadId tid = VG_(get_running_tid)();
rjwalshbc0bb832004-06-19 18:12:36 +0000467
njn12627272005-08-14 18:32:16 +0000468 mp = VG_(HT_lookup)(MAC_(mempool_list), (UWord)pool);
rjwalshbc0bb832004-06-19 18:12:36 +0000469 if (mp == NULL) {
470 MAC_(record_illegal_mempool_error)(tid, pool);
471 return;
472 }
473
njn9a463242005-08-16 03:29:50 +0000474 mc = VG_(HT_remove)(mp->chunks, (UWord)addr);
rjwalshbc0bb832004-06-19 18:12:36 +0000475 if (mc == NULL) {
476 MAC_(record_free_error)(tid, (Addr)addr);
477 return;
478 }
479
njn34582fb2005-08-11 00:06:36 +0000480 die_and_free_mem ( tid, mc, mp->rzB );
rjwalshbc0bb832004-06-19 18:12:36 +0000481}
482
njn86f12dc2005-03-14 01:16:05 +0000483/*------------------------------------------------------------*/
484/*--- Statistics printing ---*/
485/*------------------------------------------------------------*/
486
njn86f12dc2005-03-14 01:16:05 +0000487void MAC_(print_malloc_stats) ( void )
488{
njn1d0cb0d2005-08-15 01:52:02 +0000489 MAC_Chunk* mc;
njn0fd92f42005-10-06 03:32:42 +0000490 SizeT nblocks = 0;
njn1d0cb0d2005-08-15 01:52:02 +0000491 SizeT nbytes = 0;
njn86f12dc2005-03-14 01:16:05 +0000492
493 if (VG_(clo_verbosity) == 0)
494 return;
sewardj71bc3cb2005-05-19 00:25:45 +0000495 if (VG_(clo_xml))
496 return;
njn86f12dc2005-03-14 01:16:05 +0000497
498 /* Count memory still in use. */
njn1d0cb0d2005-08-15 01:52:02 +0000499 VG_(HT_ResetIter)(MAC_(malloc_list));
500 while ( (mc = VG_(HT_Next)(MAC_(malloc_list))) ) {
501 nblocks++;
502 nbytes += mc->size;
503 }
njn86f12dc2005-03-14 01:16:05 +0000504
505 VG_(message)(Vg_UserMsg,
njn0fd92f42005-10-06 03:32:42 +0000506 "malloc/free: in use at exit: %,lu bytes in %,lu blocks.",
njn1d0cb0d2005-08-15 01:52:02 +0000507 nbytes, nblocks);
njn86f12dc2005-03-14 01:16:05 +0000508 VG_(message)(Vg_UserMsg,
njn0fd92f42005-10-06 03:32:42 +0000509 "malloc/free: %,lu allocs, %,lu frees, %,lu bytes allocated.",
njn86f12dc2005-03-14 01:16:05 +0000510 cmalloc_n_mallocs,
511 cmalloc_n_frees, cmalloc_bs_mallocd);
512 if (VG_(clo_verbosity) > 1)
513 VG_(message)(Vg_UserMsg, "");
514}
515
njn3e884182003-04-15 13:03:23 +0000516/*--------------------------------------------------------------------*/
njn86f12dc2005-03-14 01:16:05 +0000517/*--- end ---*/
njn3e884182003-04-15 13:03:23 +0000518/*--------------------------------------------------------------------*/