blob: cd9a71dd043173fd21014a7804d148275ff9b9d1 [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) {
njn4775c422005-08-23 16:10:36 +0000161#if VG_WORDSIZE == 4
162 VG_(message)(Vg_UserMsg, "Warning: silly arg (%d) to %s()",
163 (Int)sizeB, fn );
164#elif VG_WORDSIZE == 8
165 VG_(message)(Vg_UserMsg, "Warning: silly arg (%lld) to %s()",
166 (Long)sizeB, fn );
167#else
168# error Unexpected word size
169#endif
nethercote7ac7f7b2004-11-02 12:36:02 +0000170 return True;
171 }
172 return False;
173}
174
175static Bool complain_about_silly_args2(SizeT n, SizeT sizeB)
176{
177 if ((SSizeT)n < 0 || (SSizeT)sizeB < 0) {
njn4775c422005-08-23 16:10:36 +0000178#if VG_WORDSIZE == 4
nethercote7ac7f7b2004-11-02 12:36:02 +0000179 VG_(message)(Vg_UserMsg, "Warning: silly args (%d,%d) to calloc()",
njn4775c422005-08-23 16:10:36 +0000180 (Int)n, (Int)sizeB);
181#elif VG_WORDSIZE == 8
182 VG_(message)(Vg_UserMsg, "Warning: silly args (%lld,%lld) to calloc()",
183 (Long)n, (Long)sizeB);
184#else
185# error Unexpected word size
186#endif
nethercote7ac7f7b2004-11-02 12:36:02 +0000187 return True;
188 }
189 return False;
190}
191
njn3e884182003-04-15 13:03:23 +0000192/* Allocate memory and note change in memory available */
njn10785452003-05-20 16:38:24 +0000193__inline__
sewardj2a99cf62004-11-24 10:44:19 +0000194void* MAC_(new_block) ( ThreadId tid,
195 Addr p, SizeT size, SizeT align, UInt rzB,
nethercote57e36b32004-07-10 14:56:28 +0000196 Bool is_zeroed, MAC_AllocKind kind, VgHashTable table)
njn3e884182003-04-15 13:03:23 +0000197{
njn3e884182003-04-15 13:03:23 +0000198 VGP_PUSHCC(VgpCliMalloc);
njn3e884182003-04-15 13:03:23 +0000199 cmalloc_n_mallocs ++;
njn3e884182003-04-15 13:03:23 +0000200
nethercote57e36b32004-07-10 14:56:28 +0000201 // Allocate and zero if necessary
202 if (p) {
njnca82cc02004-11-22 17:18:48 +0000203 tl_assert(MAC_AllocCustom == kind);
nethercote57e36b32004-07-10 14:56:28 +0000204 } else {
njnca82cc02004-11-22 17:18:48 +0000205 tl_assert(MAC_AllocCustom != kind);
nethercote57e36b32004-07-10 14:56:28 +0000206 p = (Addr)VG_(cli_malloc)( align, size );
207 if (!p) {
208 VGP_POPCC(VgpCliMalloc);
209 return NULL;
210 }
211 if (is_zeroed) VG_(memset)((void*)p, 0, size);
212 }
213
njn2a513bf2005-06-30 02:34:32 +0000214 // Only update this stat if allocation succeeded.
215 cmalloc_bs_mallocd += size;
216
njn246a9d22005-08-14 06:24:20 +0000217 VG_(HT_add_node)( table, create_MAC_Chunk(tid, p, size, kind) );
njn3e884182003-04-15 13:03:23 +0000218
njn10785452003-05-20 16:38:24 +0000219 MAC_(ban_mem_heap)( p-rzB, rzB );
njn3e884182003-04-15 13:03:23 +0000220 MAC_(new_mem_heap)( p, size, is_zeroed );
njn10785452003-05-20 16:38:24 +0000221 MAC_(ban_mem_heap)( p+size, rzB );
njn3e884182003-04-15 13:03:23 +0000222
223 VGP_POPCC(VgpCliMalloc);
rjwalshbc0bb832004-06-19 18:12:36 +0000224
nethercote57e36b32004-07-10 14:56:28 +0000225 return (void*)p;
njn3e884182003-04-15 13:03:23 +0000226}
227
njn51d827b2005-05-09 01:02:08 +0000228void* MAC_(malloc) ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +0000229{
nethercote7ac7f7b2004-11-02 12:36:02 +0000230 if (complain_about_silly_args(n, "malloc")) {
njn3e884182003-04-15 13:03:23 +0000231 return NULL;
232 } else {
sewardj2a99cf62004-11-24 10:44:19 +0000233 return MAC_(new_block) ( tid, 0, n, VG_(clo_alignment),
njn51d827b2005-05-09 01:02:08 +0000234 MAC_MALLOC_REDZONE_SZB, /*is_zeroed*/False, MAC_AllocMalloc,
nethercote57e36b32004-07-10 14:56:28 +0000235 MAC_(malloc_list));
njn3e884182003-04-15 13:03:23 +0000236 }
237}
238
njn51d827b2005-05-09 01:02:08 +0000239void* MAC_(__builtin_new) ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +0000240{
nethercote7ac7f7b2004-11-02 12:36:02 +0000241 if (complain_about_silly_args(n, "__builtin_new")) {
njn3e884182003-04-15 13:03:23 +0000242 return NULL;
243 } else {
sewardj2a99cf62004-11-24 10:44:19 +0000244 return MAC_(new_block) ( tid, 0, n, VG_(clo_alignment),
njn51d827b2005-05-09 01:02:08 +0000245 MAC_MALLOC_REDZONE_SZB, /*is_zeroed*/False, MAC_AllocNew,
nethercote57e36b32004-07-10 14:56:28 +0000246 MAC_(malloc_list));
njn3e884182003-04-15 13:03:23 +0000247 }
248}
249
njn51d827b2005-05-09 01:02:08 +0000250void* MAC_(__builtin_vec_new) ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +0000251{
nethercote7ac7f7b2004-11-02 12:36:02 +0000252 if (complain_about_silly_args(n, "__builtin_vec_new")) {
njn3e884182003-04-15 13:03:23 +0000253 return NULL;
254 } else {
sewardj2a99cf62004-11-24 10:44:19 +0000255 return MAC_(new_block) ( tid, 0, n, VG_(clo_alignment),
njn51d827b2005-05-09 01:02:08 +0000256 MAC_MALLOC_REDZONE_SZB, /*is_zeroed*/False, MAC_AllocNewVec,
nethercote57e36b32004-07-10 14:56:28 +0000257 MAC_(malloc_list));
njn3e884182003-04-15 13:03:23 +0000258 }
259}
260
njn51d827b2005-05-09 01:02:08 +0000261void* MAC_(memalign) ( ThreadId tid, SizeT align, SizeT n )
njn3e884182003-04-15 13:03:23 +0000262{
nethercote7ac7f7b2004-11-02 12:36:02 +0000263 if (complain_about_silly_args(n, "memalign")) {
njn3e884182003-04-15 13:03:23 +0000264 return NULL;
265 } else {
sewardj2a99cf62004-11-24 10:44:19 +0000266 return MAC_(new_block) ( tid, 0, n, align,
njn51d827b2005-05-09 01:02:08 +0000267 MAC_MALLOC_REDZONE_SZB, /*is_zeroed*/False, MAC_AllocMalloc,
nethercote57e36b32004-07-10 14:56:28 +0000268 MAC_(malloc_list));
njn3e884182003-04-15 13:03:23 +0000269 }
270}
271
njn51d827b2005-05-09 01:02:08 +0000272void* MAC_(calloc) ( ThreadId tid, SizeT nmemb, SizeT size1 )
njn3e884182003-04-15 13:03:23 +0000273{
nethercote7ac7f7b2004-11-02 12:36:02 +0000274 if (complain_about_silly_args2(nmemb, size1)) {
njn3e884182003-04-15 13:03:23 +0000275 return NULL;
276 } else {
sewardj2a99cf62004-11-24 10:44:19 +0000277 return MAC_(new_block) ( tid, 0, nmemb*size1, VG_(clo_alignment),
njn51d827b2005-05-09 01:02:08 +0000278 MAC_MALLOC_REDZONE_SZB, /*is_zeroed*/True, MAC_AllocMalloc,
nethercote57e36b32004-07-10 14:56:28 +0000279 MAC_(malloc_list));
njn3e884182003-04-15 13:03:23 +0000280 }
281}
282
283static
njn34582fb2005-08-11 00:06:36 +0000284void die_and_free_mem ( ThreadId tid, MAC_Chunk* mc, SizeT rzB )
njn3e884182003-04-15 13:03:23 +0000285{
286 /* Note: ban redzones again -- just in case user de-banned them
287 with a client request... */
njn10785452003-05-20 16:38:24 +0000288 MAC_(ban_mem_heap)( mc->data-rzB, rzB );
njn3e884182003-04-15 13:03:23 +0000289 MAC_(die_mem_heap)( mc->data, mc->size );
njn10785452003-05-20 16:38:24 +0000290 MAC_(ban_mem_heap)( mc->data+mc->size, rzB );
njn3e884182003-04-15 13:03:23 +0000291
njn10785452003-05-20 16:38:24 +0000292 /* Put it out of harm's way for a while, if not from a client request */
rjwalshbc0bb832004-06-19 18:12:36 +0000293 if (MAC_AllocCustom != mc->allockind) {
294 /* Record where freed */
njnd01fef72005-03-25 23:35:48 +0000295 mc->where = VG_(record_ExeContext) ( tid );
njn10785452003-05-20 16:38:24 +0000296 add_to_freed_queue ( mc );
njn4bd67b52005-08-11 00:47:10 +0000297 } else {
njn10785452003-05-20 16:38:24 +0000298 VG_(free) ( mc );
njn4bd67b52005-08-11 00:47:10 +0000299 }
njn3e884182003-04-15 13:03:23 +0000300}
301
njn10785452003-05-20 16:38:24 +0000302__inline__
sewardj2a99cf62004-11-24 10:44:19 +0000303void MAC_(handle_free) ( ThreadId tid, Addr p, UInt rzB, MAC_AllocKind kind )
njn3e884182003-04-15 13:03:23 +0000304{
njn5cc5d7e2005-08-11 02:09:25 +0000305 MAC_Chunk* mc;
njn3e884182003-04-15 13:03:23 +0000306
307 VGP_PUSHCC(VgpCliMalloc);
308
309 cmalloc_n_frees++;
310
njn9a463242005-08-16 03:29:50 +0000311 mc = VG_(HT_remove) ( MAC_(malloc_list), (UWord)p );
njn3e884182003-04-15 13:03:23 +0000312 if (mc == NULL) {
njn72718642003-07-24 08:45:32 +0000313 MAC_(record_free_error) ( tid, p );
njn9a463242005-08-16 03:29:50 +0000314 } else {
njna0793652005-08-16 03:34:56 +0000315 /* check if it is a matching free() / delete / delete [] */
njn9a463242005-08-16 03:29:50 +0000316 if (kind != mc->allockind) {
317 MAC_(record_freemismatch_error) ( tid, p, mc );
318 }
319 die_and_free_mem ( tid, mc, rzB );
njn3e884182003-04-15 13:03:23 +0000320 }
321
njn3e884182003-04-15 13:03:23 +0000322 VGP_POPCC(VgpCliMalloc);
323}
324
njn51d827b2005-05-09 01:02:08 +0000325void MAC_(free) ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +0000326{
sewardj2a99cf62004-11-24 10:44:19 +0000327 MAC_(handle_free)(
njn51d827b2005-05-09 01:02:08 +0000328 tid, (Addr)p, MAC_MALLOC_REDZONE_SZB, MAC_AllocMalloc );
njn3e884182003-04-15 13:03:23 +0000329}
330
njn51d827b2005-05-09 01:02:08 +0000331void MAC_(__builtin_delete) ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +0000332{
sewardj2a99cf62004-11-24 10:44:19 +0000333 MAC_(handle_free)(
njn51d827b2005-05-09 01:02:08 +0000334 tid, (Addr)p, MAC_MALLOC_REDZONE_SZB, MAC_AllocNew);
njn3e884182003-04-15 13:03:23 +0000335}
336
njn51d827b2005-05-09 01:02:08 +0000337void MAC_(__builtin_vec_delete) ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +0000338{
sewardj2a99cf62004-11-24 10:44:19 +0000339 MAC_(handle_free)(
njn51d827b2005-05-09 01:02:08 +0000340 tid, (Addr)p, MAC_MALLOC_REDZONE_SZB, MAC_AllocNewVec);
njn3e884182003-04-15 13:03:23 +0000341}
342
njn5cc5d7e2005-08-11 02:09:25 +0000343void* MAC_(realloc) ( ThreadId tid, void* p_old, SizeT new_size )
njn3e884182003-04-15 13:03:23 +0000344{
njn5cc5d7e2005-08-11 02:09:25 +0000345 MAC_Chunk* mc;
346 void* p_new;
347 SizeT old_size;
njn3e884182003-04-15 13:03:23 +0000348
349 VGP_PUSHCC(VgpCliMalloc);
350
351 cmalloc_n_frees ++;
352 cmalloc_n_mallocs ++;
353 cmalloc_bs_mallocd += new_size;
354
nethercote7ac7f7b2004-11-02 12:36:02 +0000355 if (complain_about_silly_args(new_size, "realloc"))
njn3e884182003-04-15 13:03:23 +0000356 return NULL;
njn3e884182003-04-15 13:03:23 +0000357
njn5cc5d7e2005-08-11 02:09:25 +0000358 /* Remove the old block */
njn9a463242005-08-16 03:29:50 +0000359 mc = VG_(HT_remove) ( MAC_(malloc_list), (UWord)p_old );
njn3e884182003-04-15 13:03:23 +0000360 if (mc == NULL) {
njn5cc5d7e2005-08-11 02:09:25 +0000361 MAC_(record_free_error) ( tid, (Addr)p_old );
njn9a463242005-08-16 03:29:50 +0000362 /* We return to the program regardless. */
njn3e884182003-04-15 13:03:23 +0000363 VGP_POPCC(VgpCliMalloc);
364 return NULL;
365 }
njn5cc5d7e2005-08-11 02:09:25 +0000366
njn3e884182003-04-15 13:03:23 +0000367 /* check if its a matching free() / delete / delete [] */
368 if (MAC_AllocMalloc != mc->allockind) {
369 /* can not realloc a range that was allocated with new or new [] */
njn5cc5d7e2005-08-11 02:09:25 +0000370 MAC_(record_freemismatch_error) ( tid, (Addr)p_old, mc );
njn3e884182003-04-15 13:03:23 +0000371 /* but keep going anyway */
372 }
373
njn5cc5d7e2005-08-11 02:09:25 +0000374 old_size = mc->size;
375
376 if (old_size == new_size) {
njn3e884182003-04-15 13:03:23 +0000377 /* size unchanged */
njnd01fef72005-03-25 23:35:48 +0000378 mc->where = VG_(record_ExeContext)(tid);
njn5cc5d7e2005-08-11 02:09:25 +0000379 p_new = p_old;
njn3e884182003-04-15 13:03:23 +0000380
njn5cc5d7e2005-08-11 02:09:25 +0000381 } else if (old_size > new_size) {
njn3e884182003-04-15 13:03:23 +0000382 /* new size is smaller */
383 MAC_(die_mem_heap)( mc->data+new_size, mc->size-new_size );
384 mc->size = new_size;
njnd01fef72005-03-25 23:35:48 +0000385 mc->where = VG_(record_ExeContext)(tid);
njn5cc5d7e2005-08-11 02:09:25 +0000386 p_new = p_old;
njn3e884182003-04-15 13:03:23 +0000387
388 } else {
389 /* new size is bigger */
njn3e884182003-04-15 13:03:23 +0000390 /* Get new memory */
njn5cc5d7e2005-08-11 02:09:25 +0000391 Addr a_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size);
njn3e884182003-04-15 13:03:23 +0000392
njn5cc5d7e2005-08-11 02:09:25 +0000393 /* First half kept and copied, second half new, red zones as normal */
394 MAC_(ban_mem_heap) ( a_new-MAC_MALLOC_REDZONE_SZB, MAC_MALLOC_REDZONE_SZB );
395 MAC_(copy_mem_heap)( (Addr)p_old, a_new, mc->size );
396 MAC_(new_mem_heap) ( a_new+mc->size, new_size-mc->size, /*init'd*/False );
397 MAC_(ban_mem_heap) ( a_new+new_size, MAC_MALLOC_REDZONE_SZB );
njn3e884182003-04-15 13:03:23 +0000398
399 /* Copy from old to new */
njn5cc5d7e2005-08-11 02:09:25 +0000400 VG_(memcpy)((void*)a_new, p_old, mc->size);
njn3e884182003-04-15 13:03:23 +0000401
402 /* Free old memory */
njn5cc5d7e2005-08-11 02:09:25 +0000403 /* Nb: we have to allocate a new MAC_Chunk for the new memory rather
404 than recycling the old one, so that any erroneous accesses to the
405 old memory are reported. */
njn34582fb2005-08-11 00:06:36 +0000406 die_and_free_mem ( tid, mc, MAC_MALLOC_REDZONE_SZB );
njn3e884182003-04-15 13:03:23 +0000407
njn5cc5d7e2005-08-11 02:09:25 +0000408 // Allocate a new chunk.
409 mc = create_MAC_Chunk( tid, a_new, new_size, MAC_AllocMalloc );
410 p_new = (void*)a_new;
njn3e884182003-04-15 13:03:23 +0000411 }
njn5cc5d7e2005-08-11 02:09:25 +0000412
413 // Now insert the new mc (with a possibly new 'data' field) into
414 // malloc_list. If this realloc() did not increase the memory size, we
415 // will have removed and then re-added mc unnecessarily. But that's ok
416 // because shrinking a block with realloc() is (presumably) much rarer
417 // than growing it, and this way simplifies the growing case.
njn246a9d22005-08-14 06:24:20 +0000418 VG_(HT_add_node)( MAC_(malloc_list), mc );
njn5cc5d7e2005-08-11 02:09:25 +0000419
420 VGP_POPCC(VgpCliMalloc);
421 return p_new;
njn3e884182003-04-15 13:03:23 +0000422}
423
rjwalshbc0bb832004-06-19 18:12:36 +0000424/* Memory pool stuff. */
425
426void MAC_(create_mempool)(Addr pool, UInt rzB, Bool is_zeroed)
427{
njn9a463242005-08-16 03:29:50 +0000428 MAC_Mempool* mp = VG_(malloc)(sizeof(MAC_Mempool));
429 mp->pool = pool;
430 mp->rzB = rzB;
431 mp->is_zeroed = is_zeroed;
432 mp->chunks = VG_(HT_construct)( 3001 ); // prime, not so big
rjwalshbc0bb832004-06-19 18:12:36 +0000433
434 /* Paranoia ... ensure this area is off-limits to the client, so
435 the mp->data field isn't visible to the leak checker. If memory
436 management is working correctly, anything pointer returned by
437 VG_(malloc) should be noaccess as far as the client is
438 concerned. */
439 if (!MAC_(check_noaccess)( (Addr)mp, sizeof(MAC_Mempool), NULL )) {
njn67993252004-11-22 18:02:32 +0000440 VG_(tool_panic)("MAC_(create_mempool): shadow area is accessible");
rjwalshbc0bb832004-06-19 18:12:36 +0000441 }
442
njn246a9d22005-08-14 06:24:20 +0000443 VG_(HT_add_node)( MAC_(mempool_list), mp );
rjwalshbc0bb832004-06-19 18:12:36 +0000444}
445
446void MAC_(destroy_mempool)(Addr pool)
447{
njn1d0cb0d2005-08-15 01:52:02 +0000448 MAC_Chunk* mc;
thughes4ad52d02004-06-27 17:37:21 +0000449 MAC_Mempool* mp;
rjwalshbc0bb832004-06-19 18:12:36 +0000450
njn12627272005-08-14 18:32:16 +0000451 mp = VG_(HT_remove) ( MAC_(mempool_list), (UWord)pool );
rjwalshbc0bb832004-06-19 18:12:36 +0000452
453 if (mp == NULL) {
sewardj76754cf2005-03-14 00:14:04 +0000454 ThreadId tid = VG_(get_running_tid)();
rjwalshbc0bb832004-06-19 18:12:36 +0000455 MAC_(record_illegal_mempool_error) ( tid, pool );
456 return;
457 }
458
njn1d0cb0d2005-08-15 01:52:02 +0000459 // Clean up the chunks, one by one
460 VG_(HT_ResetIter)(mp->chunks);
461 while ( (mc = VG_(HT_Next)(mp->chunks)) ) {
462 /* Note: ban redzones again -- just in case user de-banned them
463 with a client request... */
464 MAC_(ban_mem_heap)(mc->data-mp->rzB, mp->rzB );
465 MAC_(die_mem_heap)(mc->data, mc->size );
466 MAC_(ban_mem_heap)(mc->data+mc->size, mp->rzB );
467 }
468 // Destroy the chunk table
rjwalshbc0bb832004-06-19 18:12:36 +0000469 VG_(HT_destruct)(mp->chunks);
470
471 VG_(free)(mp);
472}
473
sewardj2a99cf62004-11-24 10:44:19 +0000474void MAC_(mempool_alloc)(ThreadId tid, Addr pool, Addr addr, SizeT size)
rjwalshbc0bb832004-06-19 18:12:36 +0000475{
njn9a463242005-08-16 03:29:50 +0000476 MAC_Mempool* mp = VG_(HT_lookup) ( MAC_(mempool_list), (UWord)pool );
rjwalshbc0bb832004-06-19 18:12:36 +0000477
478 if (mp == NULL) {
rjwalshbc0bb832004-06-19 18:12:36 +0000479 MAC_(record_illegal_mempool_error) ( tid, pool );
njn9a463242005-08-16 03:29:50 +0000480 } else {
481 MAC_(new_block)(tid, addr, size, /*ignored*/0, mp->rzB, mp->is_zeroed,
482 MAC_AllocCustom, mp->chunks);
rjwalshbc0bb832004-06-19 18:12:36 +0000483 }
rjwalshbc0bb832004-06-19 18:12:36 +0000484}
485
486void MAC_(mempool_free)(Addr pool, Addr addr)
487{
488 MAC_Mempool* mp;
rjwalshbc0bb832004-06-19 18:12:36 +0000489 MAC_Chunk* mc;
sewardj76754cf2005-03-14 00:14:04 +0000490 ThreadId tid = VG_(get_running_tid)();
rjwalshbc0bb832004-06-19 18:12:36 +0000491
njn12627272005-08-14 18:32:16 +0000492 mp = VG_(HT_lookup)(MAC_(mempool_list), (UWord)pool);
rjwalshbc0bb832004-06-19 18:12:36 +0000493 if (mp == NULL) {
494 MAC_(record_illegal_mempool_error)(tid, pool);
495 return;
496 }
497
njn9a463242005-08-16 03:29:50 +0000498 mc = VG_(HT_remove)(mp->chunks, (UWord)addr);
rjwalshbc0bb832004-06-19 18:12:36 +0000499 if (mc == NULL) {
500 MAC_(record_free_error)(tid, (Addr)addr);
501 return;
502 }
503
njn34582fb2005-08-11 00:06:36 +0000504 die_and_free_mem ( tid, mc, mp->rzB );
rjwalshbc0bb832004-06-19 18:12:36 +0000505}
506
njn86f12dc2005-03-14 01:16:05 +0000507/*------------------------------------------------------------*/
508/*--- Statistics printing ---*/
509/*------------------------------------------------------------*/
510
njn86f12dc2005-03-14 01:16:05 +0000511void MAC_(print_malloc_stats) ( void )
512{
njn1d0cb0d2005-08-15 01:52:02 +0000513 MAC_Chunk* mc;
514 UInt nblocks = 0;
515 SizeT nbytes = 0;
njn86f12dc2005-03-14 01:16:05 +0000516
517 if (VG_(clo_verbosity) == 0)
518 return;
sewardj71bc3cb2005-05-19 00:25:45 +0000519 if (VG_(clo_xml))
520 return;
njn86f12dc2005-03-14 01:16:05 +0000521
522 /* Count memory still in use. */
njn1d0cb0d2005-08-15 01:52:02 +0000523 VG_(HT_ResetIter)(MAC_(malloc_list));
524 while ( (mc = VG_(HT_Next)(MAC_(malloc_list))) ) {
525 nblocks++;
526 nbytes += mc->size;
527 }
njn86f12dc2005-03-14 01:16:05 +0000528
529 VG_(message)(Vg_UserMsg,
530 "malloc/free: in use at exit: %d bytes in %d blocks.",
njn1d0cb0d2005-08-15 01:52:02 +0000531 nbytes, nblocks);
njn86f12dc2005-03-14 01:16:05 +0000532 VG_(message)(Vg_UserMsg,
533 "malloc/free: %d allocs, %d frees, %u bytes allocated.",
534 cmalloc_n_mallocs,
535 cmalloc_n_frees, cmalloc_bs_mallocd);
536 if (VG_(clo_verbosity) > 1)
537 VG_(message)(Vg_UserMsg, "");
538}
539
njn3e884182003-04-15 13:03:23 +0000540/*--------------------------------------------------------------------*/
njn86f12dc2005-03-14 01:16:05 +0000541/*--- end ---*/
njn3e884182003-04-15 13:03:23 +0000542/*--------------------------------------------------------------------*/