njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 1 | |
| 2 | /*--------------------------------------------------------------------*/ |
| 3 | /*--- malloc/free wrappers for detecting errors and updating bits. ---*/ |
| 4 | /*--- mac_malloc_wrappers.c ---*/ |
| 5 | /*--------------------------------------------------------------------*/ |
| 6 | |
| 7 | /* |
nethercote | 137bc55 | 2003-11-14 17:47:54 +0000 | [diff] [blame] | 8 | This file is part of MemCheck, a heavyweight Valgrind tool for |
| 9 | detecting memory errors, and AddrCheck, a lightweight Valgrind tool |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 10 | for detecting memory errors. |
| 11 | |
nethercote | bb1c991 | 2004-01-04 16:43:23 +0000 | [diff] [blame] | 12 | Copyright (C) 2000-2004 Julian Seward |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 13 | 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 ... */ |
| 40 | static UInt cmalloc_n_mallocs = 0; |
| 41 | static UInt cmalloc_n_frees = 0; |
| 42 | static UInt cmalloc_bs_mallocd = 0; |
| 43 | |
| 44 | /* We want a 16B redzone on heap blocks for Addrcheck and Memcheck */ |
| 45 | UInt VG_(vg_malloc_redzone_szB) = 16; |
| 46 | |
sewardj | f9025f7 | 2003-07-12 01:41:24 +0000 | [diff] [blame] | 47 | /* Function pointers for the two skins to track interesting events. */ |
sewardj | ecf8e10 | 2003-07-12 12:11:39 +0000 | [diff] [blame] | 48 | void (*MAC_(new_mem_heap)) ( Addr a, UInt len, Bool is_inited ) = NULL; |
| 49 | void (*MAC_(ban_mem_heap)) ( Addr a, UInt len ) = NULL; |
| 50 | void (*MAC_(die_mem_heap)) ( Addr a, UInt len ) = NULL; |
| 51 | void (*MAC_(copy_mem_heap))( Addr from, Addr to, UInt len ) = NULL; |
| 52 | |
| 53 | /* Function pointers for internal sanity checking. */ |
| 54 | Bool (*MAC_(check_noaccess))( Addr a, UInt len, Addr* bad_addr ) = NULL; |
sewardj | f9025f7 | 2003-07-12 01:41:24 +0000 | [diff] [blame] | 55 | |
| 56 | |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 57 | /*------------------------------------------------------------*/ |
| 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. */ |
| 63 | VgHashTable MAC_(malloc_list) = NULL; |
| 64 | |
| 65 | /* Records blocks after freeing. */ |
| 66 | static MAC_Chunk* freed_list_start = NULL; |
| 67 | static MAC_Chunk* freed_list_end = NULL; |
| 68 | static Int freed_list_volume = 0; |
| 69 | |
| 70 | /* Put a shadow chunk on the freed blocks queue, possibly freeing up |
| 71 | some of the oldest blocks in the queue at the same time. */ |
| 72 | static void add_to_freed_queue ( MAC_Chunk* mc ) |
| 73 | { |
| 74 | MAC_Chunk* sc1; |
| 75 | |
| 76 | /* Put it at the end of the freed list */ |
| 77 | if (freed_list_end == NULL) { |
| 78 | sk_assert(freed_list_start == NULL); |
| 79 | freed_list_end = freed_list_start = mc; |
| 80 | freed_list_volume = mc->size; |
| 81 | } else { |
| 82 | sk_assert(freed_list_end->next == NULL); |
| 83 | freed_list_end->next = mc; |
| 84 | freed_list_end = mc; |
| 85 | freed_list_volume += mc->size; |
| 86 | } |
| 87 | mc->next = NULL; |
| 88 | |
| 89 | /* Release enough of the oldest blocks to bring the free queue |
| 90 | volume below vg_clo_freelist_vol. */ |
| 91 | |
| 92 | while (freed_list_volume > MAC_(clo_freelist_vol)) { |
| 93 | sk_assert(freed_list_start != NULL); |
| 94 | sk_assert(freed_list_end != NULL); |
| 95 | |
| 96 | sc1 = freed_list_start; |
| 97 | freed_list_volume -= sc1->size; |
| 98 | /* VG_(printf)("volume now %d\n", freed_list_volume); */ |
| 99 | sk_assert(freed_list_volume >= 0); |
| 100 | |
| 101 | if (freed_list_start == freed_list_end) { |
| 102 | freed_list_start = freed_list_end = NULL; |
| 103 | } else { |
| 104 | freed_list_start = sc1->next; |
| 105 | } |
| 106 | sc1->next = NULL; /* just paranoia */ |
| 107 | |
| 108 | /* free MAC_Chunk */ |
| 109 | VG_(cli_free) ( (void*)(sc1->data) ); |
| 110 | VG_(free) ( sc1 ); |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | /* Return the first shadow chunk satisfying the predicate p. */ |
| 115 | MAC_Chunk* MAC_(first_matching_freed_MAC_Chunk) ( Bool (*p)(MAC_Chunk*) ) |
| 116 | { |
| 117 | MAC_Chunk* mc; |
| 118 | |
| 119 | /* No point looking through freed blocks if we're not keeping |
| 120 | them around for a while... */ |
| 121 | for (mc = freed_list_start; mc != NULL; mc = mc->next) |
| 122 | if (p(mc)) |
| 123 | return mc; |
| 124 | |
| 125 | return NULL; |
| 126 | } |
| 127 | |
njn | 1078545 | 2003-05-20 16:38:24 +0000 | [diff] [blame] | 128 | /* Allocate its shadow chunk, put it on the appropriate list. */ |
| 129 | static |
njn | 7271864 | 2003-07-24 08:45:32 +0000 | [diff] [blame] | 130 | void add_MAC_Chunk ( Addr p, UInt size, MAC_AllocKind kind ) |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 131 | { |
| 132 | MAC_Chunk* mc; |
| 133 | |
| 134 | mc = VG_(malloc)(sizeof(MAC_Chunk)); |
| 135 | mc->data = p; |
| 136 | mc->size = size; |
| 137 | mc->allockind = kind; |
njn | 7271864 | 2003-07-24 08:45:32 +0000 | [diff] [blame] | 138 | mc->where = VG_(get_ExeContext)(VG_(get_current_or_recent_tid)()); |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 139 | |
sewardj | ecf8e10 | 2003-07-12 12:11:39 +0000 | [diff] [blame] | 140 | /* Paranoia ... ensure this area is off-limits to the client, so |
| 141 | the mc->data field isn't visible to the leak checker. If memory |
| 142 | management is working correctly, anything pointer returned by |
| 143 | VG_(malloc) should be noaccess as far as the client is |
| 144 | concerned. */ |
| 145 | if (!MAC_(check_noaccess)( (Addr)mc, sizeof(MAC_Chunk), NULL )) { |
| 146 | VG_(skin_panic)("add_MAC_chunk: shadow area is accessible"); |
| 147 | } |
sewardj | f9025f7 | 2003-07-12 01:41:24 +0000 | [diff] [blame] | 148 | |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 149 | VG_(HT_add_node)( MAC_(malloc_list), (VgHashNode*)mc ); |
| 150 | } |
| 151 | |
| 152 | /*------------------------------------------------------------*/ |
| 153 | /*--- client_malloc(), etc ---*/ |
| 154 | /*------------------------------------------------------------*/ |
| 155 | |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 156 | /* Allocate memory and note change in memory available */ |
njn | 1078545 | 2003-05-20 16:38:24 +0000 | [diff] [blame] | 157 | __inline__ |
njn | 7271864 | 2003-07-24 08:45:32 +0000 | [diff] [blame] | 158 | void MAC_(new_block) ( Addr p, UInt size, |
| 159 | UInt rzB, Bool is_zeroed, MAC_AllocKind kind ) |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 160 | { |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 161 | VGP_PUSHCC(VgpCliMalloc); |
| 162 | |
| 163 | cmalloc_n_mallocs ++; |
| 164 | cmalloc_bs_mallocd += size; |
| 165 | |
njn | 7271864 | 2003-07-24 08:45:32 +0000 | [diff] [blame] | 166 | add_MAC_Chunk( p, size, kind ); |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 167 | |
njn | 1078545 | 2003-05-20 16:38:24 +0000 | [diff] [blame] | 168 | MAC_(ban_mem_heap)( p-rzB, rzB ); |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 169 | MAC_(new_mem_heap)( p, size, is_zeroed ); |
njn | 1078545 | 2003-05-20 16:38:24 +0000 | [diff] [blame] | 170 | MAC_(ban_mem_heap)( p+size, rzB ); |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 171 | |
| 172 | VGP_POPCC(VgpCliMalloc); |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 173 | } |
| 174 | |
njn | 7271864 | 2003-07-24 08:45:32 +0000 | [diff] [blame] | 175 | void* SK_(malloc) ( Int n ) |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 176 | { |
| 177 | if (n < 0) { |
| 178 | VG_(message)(Vg_UserMsg, "Warning: silly arg (%d) to malloc()", n ); |
| 179 | return NULL; |
| 180 | } else { |
njn | 1078545 | 2003-05-20 16:38:24 +0000 | [diff] [blame] | 181 | Addr p = (Addr)VG_(cli_malloc)( VG_(clo_alignment), n ); |
njn | 7271864 | 2003-07-24 08:45:32 +0000 | [diff] [blame] | 182 | MAC_(new_block) ( p, n, VG_(vg_malloc_redzone_szB), |
njn | 1078545 | 2003-05-20 16:38:24 +0000 | [diff] [blame] | 183 | /*is_zeroed*/False, MAC_AllocMalloc ); |
| 184 | return (void*)p; |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 185 | } |
| 186 | } |
| 187 | |
njn | 7271864 | 2003-07-24 08:45:32 +0000 | [diff] [blame] | 188 | void* SK_(__builtin_new) ( Int n ) |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 189 | { |
| 190 | if (n < 0) { |
| 191 | VG_(message)(Vg_UserMsg, "Warning: silly arg (%d) to __builtin_new()", n); |
| 192 | return NULL; |
| 193 | } else { |
njn | 1078545 | 2003-05-20 16:38:24 +0000 | [diff] [blame] | 194 | Addr p = (Addr)VG_(cli_malloc)( VG_(clo_alignment), n ); |
njn | 7271864 | 2003-07-24 08:45:32 +0000 | [diff] [blame] | 195 | MAC_(new_block) ( p, n, VG_(vg_malloc_redzone_szB), |
njn | 1078545 | 2003-05-20 16:38:24 +0000 | [diff] [blame] | 196 | /*is_zeroed*/False, MAC_AllocNew ); |
| 197 | return (void*)p; |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 198 | } |
| 199 | } |
| 200 | |
njn | 7271864 | 2003-07-24 08:45:32 +0000 | [diff] [blame] | 201 | void* SK_(__builtin_vec_new) ( Int n ) |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 202 | { |
| 203 | if (n < 0) { |
| 204 | VG_(message)(Vg_UserMsg, |
| 205 | "Warning: silly arg (%d) to __builtin_vec_new()", n ); |
| 206 | return NULL; |
| 207 | } else { |
njn | 1078545 | 2003-05-20 16:38:24 +0000 | [diff] [blame] | 208 | Addr p = (Addr)VG_(cli_malloc)( VG_(clo_alignment), n ); |
njn | 7271864 | 2003-07-24 08:45:32 +0000 | [diff] [blame] | 209 | MAC_(new_block) ( p, n, VG_(vg_malloc_redzone_szB), |
njn | 1078545 | 2003-05-20 16:38:24 +0000 | [diff] [blame] | 210 | /*is_zeroed*/False, MAC_AllocNewVec ); |
| 211 | return (void*)p; |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 212 | } |
| 213 | } |
| 214 | |
njn | 7271864 | 2003-07-24 08:45:32 +0000 | [diff] [blame] | 215 | void* SK_(memalign) ( Int align, Int n ) |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 216 | { |
| 217 | if (n < 0) { |
| 218 | VG_(message)(Vg_UserMsg, "Warning: silly arg (%d) to memalign()", n); |
| 219 | return NULL; |
| 220 | } else { |
njn | 1078545 | 2003-05-20 16:38:24 +0000 | [diff] [blame] | 221 | Addr p = (Addr)VG_(cli_malloc)( align, n ); |
njn | 7271864 | 2003-07-24 08:45:32 +0000 | [diff] [blame] | 222 | MAC_(new_block) ( p, n, VG_(vg_malloc_redzone_szB), |
njn | 1078545 | 2003-05-20 16:38:24 +0000 | [diff] [blame] | 223 | /*is_zeroed*/False, MAC_AllocMalloc ); |
| 224 | return (void*)p; |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 225 | } |
| 226 | } |
| 227 | |
njn | 7271864 | 2003-07-24 08:45:32 +0000 | [diff] [blame] | 228 | void* SK_(calloc) ( Int nmemb, Int size1 ) |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 229 | { |
njn | 1078545 | 2003-05-20 16:38:24 +0000 | [diff] [blame] | 230 | Int n, i; |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 231 | |
njn | 1078545 | 2003-05-20 16:38:24 +0000 | [diff] [blame] | 232 | n = nmemb * size1; |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 233 | |
| 234 | if (nmemb < 0 || size1 < 0) { |
| 235 | VG_(message)(Vg_UserMsg, "Warning: silly args (%d,%d) to calloc()", |
| 236 | nmemb, size1 ); |
| 237 | return NULL; |
| 238 | } else { |
njn | 1078545 | 2003-05-20 16:38:24 +0000 | [diff] [blame] | 239 | Addr p = (Addr)VG_(cli_malloc)( VG_(clo_alignment), n ); |
njn | 7271864 | 2003-07-24 08:45:32 +0000 | [diff] [blame] | 240 | MAC_(new_block) ( p, n, VG_(vg_malloc_redzone_szB), |
njn | 1078545 | 2003-05-20 16:38:24 +0000 | [diff] [blame] | 241 | /*is_zeroed*/True, MAC_AllocMalloc ); |
| 242 | for (i = 0; i < n; i++) |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 243 | ((UChar*)p)[i] = 0; |
njn | 1078545 | 2003-05-20 16:38:24 +0000 | [diff] [blame] | 244 | return (void*)p; |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 245 | } |
| 246 | } |
| 247 | |
| 248 | static |
njn | 7271864 | 2003-07-24 08:45:32 +0000 | [diff] [blame] | 249 | void die_and_free_mem ( MAC_Chunk* mc, |
njn | 1078545 | 2003-05-20 16:38:24 +0000 | [diff] [blame] | 250 | MAC_Chunk** prev_chunks_next_ptr, UInt rzB ) |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 251 | { |
| 252 | /* Note: ban redzones again -- just in case user de-banned them |
| 253 | with a client request... */ |
njn | 1078545 | 2003-05-20 16:38:24 +0000 | [diff] [blame] | 254 | MAC_(ban_mem_heap)( mc->data-rzB, rzB ); |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 255 | MAC_(die_mem_heap)( mc->data, mc->size ); |
njn | 1078545 | 2003-05-20 16:38:24 +0000 | [diff] [blame] | 256 | MAC_(ban_mem_heap)( mc->data+mc->size, rzB ); |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 257 | |
| 258 | /* Remove mc from the malloclist using prev_chunks_next_ptr to |
| 259 | avoid repeating the hash table lookup. Can't remove until at least |
| 260 | after free and free_mismatch errors are done because they use |
| 261 | describe_addr() which looks for it in malloclist. */ |
| 262 | *prev_chunks_next_ptr = mc->next; |
| 263 | |
| 264 | /* Record where freed */ |
njn | 7271864 | 2003-07-24 08:45:32 +0000 | [diff] [blame] | 265 | mc->where = VG_(get_ExeContext) ( VG_(get_current_or_recent_tid)() ); |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 266 | |
njn | 1078545 | 2003-05-20 16:38:24 +0000 | [diff] [blame] | 267 | /* Put it out of harm's way for a while, if not from a client request */ |
| 268 | if (MAC_AllocCustom != mc->allockind) |
| 269 | add_to_freed_queue ( mc ); |
| 270 | else |
| 271 | VG_(free) ( mc ); |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 272 | } |
| 273 | |
| 274 | |
njn | 1078545 | 2003-05-20 16:38:24 +0000 | [diff] [blame] | 275 | __inline__ |
njn | 7271864 | 2003-07-24 08:45:32 +0000 | [diff] [blame] | 276 | void MAC_(handle_free) ( Addr p, UInt rzB, MAC_AllocKind kind ) |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 277 | { |
| 278 | MAC_Chunk* mc; |
| 279 | MAC_Chunk** prev_chunks_next_ptr; |
njn | 7271864 | 2003-07-24 08:45:32 +0000 | [diff] [blame] | 280 | ThreadId tid = VG_(get_current_or_recent_tid)(); |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 281 | |
| 282 | VGP_PUSHCC(VgpCliMalloc); |
| 283 | |
| 284 | cmalloc_n_frees++; |
| 285 | |
| 286 | mc = (MAC_Chunk*)VG_(HT_get_node) ( MAC_(malloc_list), (UInt)p, |
| 287 | (VgHashNode***)&prev_chunks_next_ptr ); |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 288 | if (mc == NULL) { |
njn | 7271864 | 2003-07-24 08:45:32 +0000 | [diff] [blame] | 289 | MAC_(record_free_error) ( tid, p ); |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 290 | VGP_POPCC(VgpCliMalloc); |
| 291 | return; |
| 292 | } |
| 293 | |
| 294 | /* check if its a matching free() / delete / delete [] */ |
| 295 | if (kind != mc->allockind) { |
njn | 7271864 | 2003-07-24 08:45:32 +0000 | [diff] [blame] | 296 | MAC_(record_freemismatch_error) ( tid, p ); |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 297 | } |
| 298 | |
njn | 7271864 | 2003-07-24 08:45:32 +0000 | [diff] [blame] | 299 | die_and_free_mem ( mc, prev_chunks_next_ptr, rzB ); |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 300 | VGP_POPCC(VgpCliMalloc); |
| 301 | } |
| 302 | |
njn | 7271864 | 2003-07-24 08:45:32 +0000 | [diff] [blame] | 303 | void SK_(free) ( void* p ) |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 304 | { |
njn | 7271864 | 2003-07-24 08:45:32 +0000 | [diff] [blame] | 305 | MAC_(handle_free)((Addr)p, VG_(vg_malloc_redzone_szB), MAC_AllocMalloc); |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 306 | } |
| 307 | |
njn | 7271864 | 2003-07-24 08:45:32 +0000 | [diff] [blame] | 308 | void SK_(__builtin_delete) ( void* p ) |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 309 | { |
njn | 7271864 | 2003-07-24 08:45:32 +0000 | [diff] [blame] | 310 | MAC_(handle_free)((Addr)p, VG_(vg_malloc_redzone_szB), MAC_AllocNew); |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 311 | } |
| 312 | |
njn | 7271864 | 2003-07-24 08:45:32 +0000 | [diff] [blame] | 313 | void SK_(__builtin_vec_delete) ( void* p ) |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 314 | { |
njn | 7271864 | 2003-07-24 08:45:32 +0000 | [diff] [blame] | 315 | MAC_(handle_free)((Addr)p, VG_(vg_malloc_redzone_szB), MAC_AllocNewVec); |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 316 | } |
| 317 | |
njn | 7271864 | 2003-07-24 08:45:32 +0000 | [diff] [blame] | 318 | void* SK_(realloc) ( void* p, Int new_size ) |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 319 | { |
| 320 | MAC_Chunk *mc; |
| 321 | MAC_Chunk **prev_chunks_next_ptr; |
| 322 | UInt i; |
njn | 7271864 | 2003-07-24 08:45:32 +0000 | [diff] [blame] | 323 | ThreadId tid = VG_(get_current_or_recent_tid)(); |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 324 | |
| 325 | VGP_PUSHCC(VgpCliMalloc); |
| 326 | |
| 327 | cmalloc_n_frees ++; |
| 328 | cmalloc_n_mallocs ++; |
| 329 | cmalloc_bs_mallocd += new_size; |
| 330 | |
| 331 | if (new_size < 0) { |
| 332 | VG_(message)(Vg_UserMsg, |
| 333 | "Warning: silly arg (%d) to realloc()", new_size ); |
| 334 | return NULL; |
| 335 | } |
| 336 | |
| 337 | /* First try and find the block. */ |
| 338 | mc = (MAC_Chunk*)VG_(HT_get_node) ( MAC_(malloc_list), (UInt)p, |
| 339 | (VgHashNode***)&prev_chunks_next_ptr ); |
| 340 | |
| 341 | if (mc == NULL) { |
njn | 7271864 | 2003-07-24 08:45:32 +0000 | [diff] [blame] | 342 | MAC_(record_free_error) ( tid, (Addr)p ); |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 343 | /* Perhaps we should return to the program regardless. */ |
| 344 | VGP_POPCC(VgpCliMalloc); |
| 345 | return NULL; |
| 346 | } |
| 347 | |
| 348 | /* check if its a matching free() / delete / delete [] */ |
| 349 | if (MAC_AllocMalloc != mc->allockind) { |
| 350 | /* can not realloc a range that was allocated with new or new [] */ |
njn | 7271864 | 2003-07-24 08:45:32 +0000 | [diff] [blame] | 351 | MAC_(record_freemismatch_error) ( tid, (Addr)p ); |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 352 | /* but keep going anyway */ |
| 353 | } |
| 354 | |
| 355 | if (mc->size == new_size) { |
| 356 | /* size unchanged */ |
njn | 398044f | 2003-07-24 17:39:59 +0000 | [diff] [blame] | 357 | mc->where = VG_(get_ExeContext)(tid); |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 358 | VGP_POPCC(VgpCliMalloc); |
| 359 | return p; |
| 360 | |
| 361 | } else if (mc->size > new_size) { |
| 362 | /* new size is smaller */ |
| 363 | MAC_(die_mem_heap)( mc->data+new_size, mc->size-new_size ); |
| 364 | mc->size = new_size; |
njn | 398044f | 2003-07-24 17:39:59 +0000 | [diff] [blame] | 365 | mc->where = VG_(get_ExeContext)(tid); |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 366 | VGP_POPCC(VgpCliMalloc); |
| 367 | return p; |
| 368 | |
| 369 | } else { |
| 370 | /* new size is bigger */ |
| 371 | Addr p_new; |
| 372 | |
| 373 | /* Get new memory */ |
| 374 | p_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size); |
| 375 | |
| 376 | /* First half kept and copied, second half new, |
| 377 | red zones as normal */ |
| 378 | MAC_(ban_mem_heap) ( p_new-VG_(vg_malloc_redzone_szB), |
| 379 | VG_(vg_malloc_redzone_szB) ); |
| 380 | MAC_(copy_mem_heap)( (Addr)p, p_new, mc->size ); |
| 381 | MAC_(new_mem_heap) ( p_new+mc->size, new_size-mc->size, /*inited*/False ); |
| 382 | MAC_(ban_mem_heap) ( p_new+new_size, VG_(vg_malloc_redzone_szB) ); |
| 383 | |
| 384 | /* Copy from old to new */ |
| 385 | for (i = 0; i < mc->size; i++) |
| 386 | ((UChar*)p_new)[i] = ((UChar*)p)[i]; |
| 387 | |
| 388 | /* Free old memory */ |
njn | 7271864 | 2003-07-24 08:45:32 +0000 | [diff] [blame] | 389 | die_and_free_mem ( mc, prev_chunks_next_ptr, |
njn | 1078545 | 2003-05-20 16:38:24 +0000 | [diff] [blame] | 390 | VG_(vg_malloc_redzone_szB) ); |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 391 | |
| 392 | /* this has to be after die_and_free_mem, otherwise the |
| 393 | former succeeds in shorting out the new block, not the |
| 394 | old, in the case when both are on the same list. */ |
njn | 7271864 | 2003-07-24 08:45:32 +0000 | [diff] [blame] | 395 | add_MAC_Chunk ( p_new, new_size, MAC_AllocMalloc ); |
njn | 3e88418 | 2003-04-15 13:03:23 +0000 | [diff] [blame] | 396 | |
| 397 | VGP_POPCC(VgpCliMalloc); |
| 398 | return (void*)p_new; |
| 399 | } |
| 400 | } |
| 401 | |
| 402 | void MAC_(print_malloc_stats) ( void ) |
| 403 | { |
| 404 | UInt nblocks = 0, nbytes = 0; |
| 405 | |
| 406 | /* Mmm... more lexical scoping */ |
| 407 | void count_one_chunk(VgHashNode* node) { |
| 408 | MAC_Chunk* mc = (MAC_Chunk*)node; |
| 409 | nblocks ++; |
| 410 | nbytes += mc->size; |
| 411 | } |
| 412 | |
| 413 | if (VG_(clo_verbosity) == 0) |
| 414 | return; |
| 415 | |
| 416 | /* Count memory still in use. */ |
| 417 | VG_(HT_apply_to_all_nodes)(MAC_(malloc_list), count_one_chunk); |
| 418 | |
| 419 | VG_(message)(Vg_UserMsg, |
| 420 | "malloc/free: in use at exit: %d bytes in %d blocks.", |
| 421 | nbytes, nblocks); |
| 422 | VG_(message)(Vg_UserMsg, |
| 423 | "malloc/free: %d allocs, %d frees, %u bytes allocated.", |
| 424 | cmalloc_n_mallocs, |
| 425 | cmalloc_n_frees, cmalloc_bs_mallocd); |
| 426 | if (VG_(clo_verbosity) > 1) |
| 427 | VG_(message)(Vg_UserMsg, ""); |
| 428 | } |
| 429 | |
| 430 | /*--------------------------------------------------------------------*/ |
| 431 | /*--- end mac_malloc_wrappers.c ---*/ |
| 432 | /*--------------------------------------------------------------------*/ |