1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- malloc/free wrappers for detecting errors and updating bits. ---*/
4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---                                         mc_malloc_wrappers.c ---*/
5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This file is part of MemCheck, a heavyweight Valgrind tool for
9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   detecting memory errors.
10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Copyright (C) 2000-2011 Julian Seward
12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      jseward@acm.org
13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This program is free software; you can redistribute it and/or
15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modify it under the terms of the GNU General Public License as
16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   published by the Free Software Foundation; either version 2 of the
17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   License, or (at your option) any later version.
18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This program is distributed in the hope that it will be useful, but
20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   WITHOUT ANY WARRANTY; without even the implied warranty of
21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   General Public License for more details.
23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   You should have received a copy of the GNU General Public License
25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   along with this program; if not, write to the Free Software
26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   02111-1307, USA.
28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The GNU General Public License is contained in the file COPYING.
30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_basics.h"
33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_execontext.h"
34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_hashtable.h"
35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_libcbase.h"
36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_libcassert.h"
37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_libcprint.h"
38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_mallocfree.h"
39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_options.h"
40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_replacemalloc.h"
41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_threadstate.h"
42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_tooliface.h"     // Needed for mc_include.h
43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_stacktrace.h"    // For VG_(get_and_pp_StackTrace)
44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "mc_include.h"
46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Defns                                                ---*/
49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Stats ... */
52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic SizeT cmalloc_n_mallocs  = 0;
53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic SizeT cmalloc_n_frees    = 0;
54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ULong cmalloc_bs_mallocd = 0;
55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* For debug printing to do with mempools: what stack trace
57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   depth to show. */
58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define MEMPOOL_DEBUG_STACKTRACE_DEPTH 16
59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Tracking malloc'd and free'd blocks                  ---*/
63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Record malloc'd blocks. */
66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownVgHashTable MC_(malloc_list) = NULL;
67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
68f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root/* Memory pools: a hash table of MC_Mempools.  Search key is
69f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   MC_Mempool::pool. */
70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownVgHashTable MC_(mempool_list) = NULL;
71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Records blocks after freeing. */
73b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* Blocks freed by the client are queued in one of two lists of
74b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   freed blocks not yet physically freed:
75b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   "big blocks" freed list.
76b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   "small blocks" freed list
77b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   The blocks with a size >= MC_(clo_freelist_big_blocks)
78b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   are linked in the big blocks freed list.
79b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   This allows a client to allocate and free big blocks
80b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   (e.g. bigger than VG_(clo_freelist_vol)) without losing
81b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   immediately all protection against dangling pointers.
82b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   position [0] is for big blocks, [1] is for small blocks. */
83b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic MC_Chunk* freed_list_start[2]  = {NULL, NULL};
84b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic MC_Chunk* freed_list_end[2]    = {NULL, NULL};
85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Put a shadow chunk on the freed blocks queue, possibly freeing up
87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   some of the oldest blocks in the queue at the same time. */
88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void add_to_freed_queue ( MC_Chunk* mc )
89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   const Bool show = False;
91b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   const int l = (mc->szB >= MC_(clo_freelist_big_blocks) ? 0 : 1);
92b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
93b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* Put it at the end of the freed list, unless the block
94b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      would be directly released any way : in this case, we
95b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      put it at the head of the freed list. */
96b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (freed_list_end[l] == NULL) {
97b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      tl_assert(freed_list_start[l] == NULL);
98b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      mc->next = NULL;
99b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      freed_list_end[l]    = freed_list_start[l] = mc;
100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
101b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      tl_assert(freed_list_end[l]->next == NULL);
102b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (mc->szB >= MC_(clo_freelist_vol)) {
103b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         mc->next = freed_list_start[l];
104b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         freed_list_start[l] = mc;
1059bea4c13fca0e3bb4b719dcb3ed63d47d479294eKenny Root      } else {
106b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         mc->next = NULL;
107b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         freed_list_end[l]->next = mc;
108b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         freed_list_end[l]       = mc;
1099bea4c13fca0e3bb4b719dcb3ed63d47d479294eKenny Root      }
110b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
111b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VG_(free_queue_volume) += (Long)mc->szB;
112b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (show)
113b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(printf)("mc_freelist: acquire: volume now %lld\n",
114b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  VG_(free_queue_volume));
115b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VG_(free_queue_length)++;
116b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
1179bea4c13fca0e3bb4b719dcb3ed63d47d479294eKenny Root
118b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* Release enough of the oldest blocks to bring the free queue
119b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   volume below vg_clo_freelist_vol.
120b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Start with big block list first.
121b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   On entry, VG_(free_queue_volume) must be > MC_(clo_freelist_vol).
122b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   On exit, VG_(free_queue_volume) will be <= MC_(clo_freelist_vol). */
123b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic void release_oldest_block(void)
124b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
125b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   const Bool show = False;
126b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   int i;
127b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   tl_assert (VG_(free_queue_volume) > MC_(clo_freelist_vol));
128b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   tl_assert (freed_list_start[0] != NULL || freed_list_start[1] != NULL);
129b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
130b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   for (i = 0; i < 2; i++) {
131b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      while (VG_(free_queue_volume) > MC_(clo_freelist_vol)
132b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov             && freed_list_start[i] != NULL) {
133b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         MC_Chunk* mc1;
134b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         tl_assert(freed_list_end[i] != NULL);
135b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
136b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         mc1 = freed_list_start[i];
137b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         VG_(free_queue_volume) -= (Long)mc1->szB;
138b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         VG_(free_queue_length)--;
139b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (show)
140b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            VG_(printf)("mc_freelist: discard: volume now %lld\n",
141b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                        VG_(free_queue_volume));
142b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         tl_assert(VG_(free_queue_volume) >= 0);
143b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
144b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (freed_list_start[i] == freed_list_end[i]) {
145b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            freed_list_start[i] = freed_list_end[i] = NULL;
146b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         } else {
147b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            freed_list_start[i] = mc1->next;
148b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         }
149b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         mc1->next = NULL; /* just paranoia */
150b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         /* free MC_Chunk */
151b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (MC_AllocCustom != mc1->allockind)
152b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            VG_(cli_free) ( (void*)(mc1->data) );
153b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         VG_(free) ( mc1 );
154b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       }
155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
158b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy StepanovMC_Chunk* MC_(get_freed_block_bracketting) (Addr a)
159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
160b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   int i;
161b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   for (i = 0; i < 2; i++) {
162b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      MC_Chunk*  mc;
163b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      mc = freed_list_start[i];
164b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      while (mc) {
165b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (VG_(addr_is_in_block)( a, mc->data, mc->szB,
166b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                    MC_MALLOC_REDZONE_SZB ))
167b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            return mc;
168b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         mc = mc->next;
169b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
170b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
171b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   return NULL;
172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
174b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* Allocate a shadow chunk, put it on the appropriate list.
175b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   If needed, release oldest blocks from freed list. */
176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownMC_Chunk* create_MC_Chunk ( ExeContext* ec, Addr p, SizeT szB,
178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            MC_AllocKind kind)
179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MC_Chunk* mc  = VG_(malloc)("mc.cMC.1 (a MC_Chunk)", sizeof(MC_Chunk));
181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mc->data      = p;
182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mc->szB       = szB;
183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mc->allockind = kind;
184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mc->where     = ec;
185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
186b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* Each time a new MC_Chunk is created, release oldest blocks
187b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if the free list volume is exceeded. */
188b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (VG_(free_queue_volume) > MC_(clo_freelist_vol))
189b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      release_oldest_block();
190b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Paranoia ... ensure the MC_Chunk is off-limits to the client, so
192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the mc->data field isn't visible to the leak checker.  If memory
193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      management is working correctly, any pointer returned by VG_(malloc)
194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      should be noaccess as far as the client is concerned. */
195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!MC_(check_mem_is_noaccess)( (Addr)mc, sizeof(MC_Chunk), NULL )) {
196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(tool_panic)("create_MC_Chunk: shadow area is accessible");
197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return mc;
199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- client_malloc(), etc                                 ---*/
203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// XXX: should make this a proper error (bug #79311).
206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool complain_about_silly_args(SizeT sizeB, Char* fn)
207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Cast to a signed type to catch any unexpectedly negative args.  We're
209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // assuming here that the size asked for is not greater than 2^31 bytes
210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // (for 32-bit platforms) or 2^63 bytes (for 64-bit platforms).
211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((SSizeT)sizeB < 0) {
212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!VG_(clo_xml))
213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)(Vg_UserMsg, "Warning: silly arg (%ld) to %s()\n",
214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      (SSizeT)sizeB, fn );
215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool complain_about_silly_args2(SizeT n, SizeT sizeB)
221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((SSizeT)n < 0 || (SSizeT)sizeB < 0) {
223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!VG_(clo_xml))
224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)(Vg_UserMsg,
225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "Warning: silly args (%ld,%ld) to calloc()\n",
226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      (SSizeT)n, (SSizeT)sizeB);
227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Allocate memory and note change in memory available */
233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid* MC_(new_block) ( ThreadId tid,
234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       Addr p, SizeT szB, SizeT alignB,
235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       Bool is_zeroed, MC_AllocKind kind, VgHashTable table)
236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ExeContext* ec;
238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cmalloc_n_mallocs ++;
240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Allocate and zero if necessary
242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (p) {
243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(MC_AllocCustom == kind);
244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(MC_AllocCustom != kind);
246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      p = (Addr)VG_(cli_malloc)( alignB, szB );
247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!p) {
248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return NULL;
249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (is_zeroed) {
251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(memset)((void*)p, 0, szB);
252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else
253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (MC_(clo_malloc_fill) != -1) {
254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(MC_(clo_malloc_fill) >= 0x00 && MC_(clo_malloc_fill) <= 0xFF);
255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(memset)((void*)p, MC_(clo_malloc_fill), szB);
256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Only update this stat if allocation succeeded.
260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cmalloc_bs_mallocd += (ULong)szB;
261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ec = VG_(record_ExeContext)(tid, 0/*first_ip_delta*/);
263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(ec);
264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(HT_add_node)( table, create_MC_Chunk(ec, p, szB, kind) );
266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (is_zeroed)
268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      MC_(make_mem_defined)( p, szB );
269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else {
270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt ecu = VG_(get_ECU_from_ExeContext)(ec);
271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(VG_(is_plausible_ECU)(ecu));
272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      MC_(make_mem_undefined_w_otag)( p, szB, ecu | MC_OKIND_HEAP );
273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return (void*)p;
276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid* MC_(malloc) ( ThreadId tid, SizeT n )
279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (complain_about_silly_args(n, "malloc")) {
281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return NULL;
282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return MC_(new_block) ( tid, 0, n, VG_(clo_alignment),
284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /*is_zeroed*/False, MC_AllocMalloc, MC_(malloc_list));
285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid* MC_(__builtin_new) ( ThreadId tid, SizeT n )
289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (complain_about_silly_args(n, "__builtin_new")) {
291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return NULL;
292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return MC_(new_block) ( tid, 0, n, VG_(clo_alignment),
294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /*is_zeroed*/False, MC_AllocNew, MC_(malloc_list));
295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid* MC_(__builtin_vec_new) ( ThreadId tid, SizeT n )
299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (complain_about_silly_args(n, "__builtin_vec_new")) {
301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return NULL;
302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return MC_(new_block) ( tid, 0, n, VG_(clo_alignment),
304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /*is_zeroed*/False, MC_AllocNewVec, MC_(malloc_list));
305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid* MC_(memalign) ( ThreadId tid, SizeT alignB, SizeT n )
309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (complain_about_silly_args(n, "memalign")) {
311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return NULL;
312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return MC_(new_block) ( tid, 0, n, alignB,
314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /*is_zeroed*/False, MC_AllocMalloc, MC_(malloc_list));
315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid* MC_(calloc) ( ThreadId tid, SizeT nmemb, SizeT size1 )
319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (complain_about_silly_args2(nmemb, size1)) {
321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return NULL;
322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return MC_(new_block) ( tid, 0, nmemb*size1, VG_(clo_alignment),
324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /*is_zeroed*/True, MC_AllocMalloc, MC_(malloc_list));
325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid die_and_free_mem ( ThreadId tid, MC_Chunk* mc, SizeT rzB )
330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (MC_(clo_free_fill) != -1) {
332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(MC_(clo_free_fill) >= 0x00 && MC_(clo_free_fill) <= 0xFF);
333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(memset)((void*)mc->data, MC_(clo_free_fill), mc->szB);
334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Note: make redzones noaccess again -- just in case user made them
337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      accessible with a client request... */
338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MC_(make_mem_noaccess)( mc->data-rzB, mc->szB + 2*rzB );
339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Record where freed */
341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mc->where = VG_(record_ExeContext) ( tid, 0/*first_ip_delta*/ );
342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Put it out of harm's way for a while */
343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   add_to_freed_queue ( mc );
344b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* If the free list volume is bigger than MC_(clo_freelist_vol),
345b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      we wait till the next block allocation to release blocks.
346b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      This increase the chance to discover dangling pointer usage,
347b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      even for big blocks being freed by the client. */
348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid MC_(handle_free) ( ThreadId tid, Addr p, UInt rzB, MC_AllocKind kind )
351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MC_Chunk* mc;
353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cmalloc_n_frees++;
355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mc = VG_(HT_remove) ( MC_(malloc_list), (UWord)p );
357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (mc == NULL) {
358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      MC_(record_free_error) ( tid, p );
359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* check if it is a matching free() / delete / delete [] */
361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (kind != mc->allockind) {
362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(p == mc->data);
363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         MC_(record_freemismatch_error) ( tid, mc );
364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      die_and_free_mem ( tid, mc, rzB );
366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid MC_(free) ( ThreadId tid, void* p )
370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MC_(handle_free)(
372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tid, (Addr)p, MC_MALLOC_REDZONE_SZB, MC_AllocMalloc );
373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid MC_(__builtin_delete) ( ThreadId tid, void* p )
376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MC_(handle_free)(
378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tid, (Addr)p, MC_MALLOC_REDZONE_SZB, MC_AllocNew);
379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid MC_(__builtin_vec_delete) ( ThreadId tid, void* p )
382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MC_(handle_free)(
384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tid, (Addr)p, MC_MALLOC_REDZONE_SZB, MC_AllocNewVec);
385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid* MC_(realloc) ( ThreadId tid, void* p_old, SizeT new_szB )
388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MC_Chunk* mc;
390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   void*     p_new;
391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SizeT     old_szB;
392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cmalloc_n_frees ++;
394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cmalloc_n_mallocs ++;
395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cmalloc_bs_mallocd += (ULong)new_szB;
396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (complain_about_silly_args(new_szB, "realloc"))
398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return NULL;
399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Remove the old block */
401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mc = VG_(HT_remove) ( MC_(malloc_list), (UWord)p_old );
402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (mc == NULL) {
403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      MC_(record_free_error) ( tid, (Addr)p_old );
404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* We return to the program regardless. */
405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return NULL;
406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* check if its a matching free() / delete / delete [] */
409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (MC_AllocMalloc != mc->allockind) {
410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* can not realloc a range that was allocated with new or new [] */
411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert((Addr)p_old == mc->data);
412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      MC_(record_freemismatch_error) ( tid, mc );
413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* but keep going anyway */
414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   old_szB = mc->szB;
417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* In all cases, even when the new size is smaller or unchanged, we
419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      reallocate and copy the contents, and make the old block
420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      inaccessible.  This is so as to guarantee to catch all cases of
421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      accesses via the old address after reallocation, regardless of
422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the change in size.  (Of course the ability to detect accesses
423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      to the old block also depends on the size of the freed blocks
424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      queue). */
425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (new_szB <= old_szB) {
427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* new size is smaller or the same */
428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Addr a_new;
429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Get new memory */
430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      a_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_szB);
431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (a_new) {
433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ExeContext* ec;
434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ec = VG_(record_ExeContext)(tid, 0/*first_ip_delta*/);
436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(ec);
437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Retained part is copied, red zones set as normal */
439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         MC_(make_mem_noaccess)( a_new-MC_MALLOC_REDZONE_SZB,
440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 MC_MALLOC_REDZONE_SZB );
441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         MC_(copy_address_range_state) ( (Addr)p_old, a_new, new_szB );
442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         MC_(make_mem_noaccess)        ( a_new+new_szB, MC_MALLOC_REDZONE_SZB );
443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Copy from old to new */
445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(memcpy)((void*)a_new, p_old, new_szB);
446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Possibly fill freed area with specified junk. */
448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (MC_(clo_free_fill) != -1) {
449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            tl_assert(MC_(clo_free_fill) >= 0x00 && MC_(clo_free_fill) <= 0xFF);
450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(memset)((void*)p_old, MC_(clo_free_fill), old_szB);
451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Free old memory */
454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Nb: we have to allocate a new MC_Chunk for the new memory rather
455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            than recycling the old one, so that any erroneous accesses to the
456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            old memory are reported. */
457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         die_and_free_mem ( tid, mc, MC_MALLOC_REDZONE_SZB );
458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // Allocate a new chunk.
460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mc = create_MC_Chunk( ec, a_new, new_szB, MC_AllocMalloc );
461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      p_new = (void*)a_new;
464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* new size is bigger */
467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Addr a_new;
468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(old_szB < new_szB);
469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Get new memory */
470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      a_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_szB);
471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (a_new) {
473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt        ecu;
474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ExeContext* ec;
475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ec = VG_(record_ExeContext)(tid, 0/*first_ip_delta*/);
477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(ec);
478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ecu = VG_(get_ECU_from_ExeContext)(ec);
479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(VG_(is_plausible_ECU)(ecu));
480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* First half kept and copied, second half new, red zones as normal */
482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         MC_(make_mem_noaccess)( a_new-MC_MALLOC_REDZONE_SZB,
483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 MC_MALLOC_REDZONE_SZB );
484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         MC_(copy_address_range_state) ( (Addr)p_old, a_new, mc->szB );
485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         MC_(make_mem_undefined_w_otag)( a_new+mc->szB, new_szB-mc->szB,
486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                        ecu | MC_OKIND_HEAP );
487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         MC_(make_mem_noaccess)        ( a_new+new_szB, MC_MALLOC_REDZONE_SZB );
488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Possibly fill new area with specified junk */
490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (MC_(clo_malloc_fill) != -1) {
491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            tl_assert(MC_(clo_malloc_fill) >= 0x00
492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      && MC_(clo_malloc_fill) <= 0xFF);
493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(memset)((void*)(a_new+old_szB), MC_(clo_malloc_fill),
494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                new_szB-old_szB);
495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Copy from old to new */
498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(memcpy)((void*)a_new, p_old, mc->szB);
499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Possibly fill freed area with specified junk. */
501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (MC_(clo_free_fill) != -1) {
502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            tl_assert(MC_(clo_free_fill) >= 0x00 && MC_(clo_free_fill) <= 0xFF);
503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(memset)((void*)p_old, MC_(clo_free_fill), old_szB);
504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Free old memory */
507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Nb: we have to allocate a new MC_Chunk for the new memory rather
508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            than recycling the old one, so that any erroneous accesses to the
509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            old memory are reported. */
510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         die_and_free_mem ( tid, mc, MC_MALLOC_REDZONE_SZB );
511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // Allocate a new chunk.
513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mc = create_MC_Chunk( ec, a_new, new_szB, MC_AllocMalloc );
514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      p_new = (void*)a_new;
517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Now insert the new mc (with a possibly new 'data' field) into
520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // malloc_list.  If this realloc() did not increase the memory size, we
521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // will have removed and then re-added mc unnecessarily.  But that's ok
522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // because shrinking a block with realloc() is (presumably) much rarer
523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // than growing it, and this way simplifies the growing case.
524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(HT_add_node)( MC_(malloc_list), mc );
525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return p_new;
527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSizeT MC_(malloc_usable_size) ( ThreadId tid, void* p )
530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MC_Chunk* mc = VG_(HT_lookup) ( MC_(malloc_list), (UWord)p );
532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // There may be slop, but pretend there isn't because only the asked-for
534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // area will be marked as addressable.
535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return ( mc ? mc->szB : 0 );
536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
538b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* This handles the in place resize of a block, as performed by the
539b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VALGRIND_RESIZEINPLACE_BLOCK client request.  It is unrelated to,
540b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   and not used for, handling of the normal libc realloc()
541b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   function. */
542b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovvoid MC_(handle_resizeInPlace)(ThreadId tid, Addr p,
543b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                               SizeT oldSizeB, SizeT newSizeB, SizeT rzB)
544b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
545b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   MC_Chunk* mc = VG_(HT_lookup) ( MC_(malloc_list), (UWord)p );
546b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (!mc || mc->szB != oldSizeB || newSizeB == 0) {
547b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* Reject if: p is not found, or oldSizeB is wrong,
548b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         or new block would be empty. */
549b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      MC_(record_free_error) ( tid, p );
550b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      return;
551b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
552b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
553b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (oldSizeB == newSizeB)
554b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      return;
555b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
556b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   mc->szB = newSizeB;
557b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (newSizeB < oldSizeB) {
558b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      MC_(make_mem_noaccess)( p + newSizeB, oldSizeB - newSizeB + rzB );
559b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   } else {
560b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      ExeContext* ec  = VG_(record_ExeContext)(tid, 0/*first_ip_delta*/);
561b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      UInt        ecu = VG_(get_ECU_from_ExeContext)(ec);
562b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      MC_(make_mem_undefined_w_otag)( p + oldSizeB, newSizeB - oldSizeB,
563b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                      ecu | MC_OKIND_HEAP );
564b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (rzB > 0)
565b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         MC_(make_mem_noaccess)( p + newSizeB, rzB );
566b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
567b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
568b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
570f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root/*------------------------------------------------------------*/
571f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root/*--- Memory pool stuff.                                   ---*/
572f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root/*------------------------------------------------------------*/
573f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
574f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root/* Set to 1 for intensive sanity checking.  Is very expensive though
575f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   and should not be used in production scenarios.  See #255966. */
576f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root#define MP_DETAILED_SANITY_CHECKS 0
577f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
578f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Rootstatic void check_mempool_sane(MC_Mempool* mp); /*forward*/
579f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid MC_(create_mempool)(Addr pool, UInt rzB, Bool is_zeroed)
582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MC_Mempool* mp;
584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_verbosity) > 2) {
586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(message)(Vg_UserMsg, "create_mempool(0x%lx, %d, %d)\n",
587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               pool, rzB, is_zeroed);
588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(get_and_pp_StackTrace)
589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         (VG_(get_running_tid)(), MEMPOOL_DEBUG_STACKTRACE_DEPTH);
590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mp = VG_(HT_lookup)(MC_(mempool_list), (UWord)pool);
593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (mp != NULL) {
594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     VG_(tool_panic)("MC_(create_mempool): duplicate pool creation");
595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mp = VG_(malloc)("mc.cm.1", sizeof(MC_Mempool));
598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mp->pool       = pool;
599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mp->rzB        = rzB;
600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mp->is_zeroed  = is_zeroed;
601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mp->chunks     = VG_(HT_construct)( "MC_(create_mempool)" );
602f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   check_mempool_sane(mp);
603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Paranoia ... ensure this area is off-limits to the client, so
605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the mp->data field isn't visible to the leak checker.  If memory
606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      management is working correctly, anything pointer returned by
607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(malloc) should be noaccess as far as the client is
608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      concerned. */
609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!MC_(check_mem_is_noaccess)( (Addr)mp, sizeof(MC_Mempool), NULL )) {
610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(tool_panic)("MC_(create_mempool): shadow area is accessible");
611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(HT_add_node)( MC_(mempool_list), mp );
614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid MC_(destroy_mempool)(Addr pool)
617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MC_Chunk*   mc;
619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MC_Mempool* mp;
620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_verbosity) > 2) {
622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(message)(Vg_UserMsg, "destroy_mempool(0x%lx)\n", pool);
623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(get_and_pp_StackTrace)
624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         (VG_(get_running_tid)(), MEMPOOL_DEBUG_STACKTRACE_DEPTH);
625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mp = VG_(HT_remove) ( MC_(mempool_list), (UWord)pool );
628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (mp == NULL) {
630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ThreadId tid = VG_(get_running_tid)();
631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      MC_(record_illegal_mempool_error) ( tid, pool );
632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;
633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
634f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   check_mempool_sane(mp);
635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Clean up the chunks, one by one
637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(HT_ResetIter)(mp->chunks);
638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while ( (mc = VG_(HT_Next)(mp->chunks)) ) {
639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Note: make redzones noaccess again -- just in case user made them
640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         accessible with a client request... */
641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      MC_(make_mem_noaccess)(mc->data-mp->rzB, mc->szB + 2*mp->rzB );
642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Destroy the chunk table
644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(HT_destruct)(mp->chunks);
645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(free)(mp);
647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int
650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmp_compar(void* n1, void* n2)
651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MC_Chunk* mc1 = *(MC_Chunk**)n1;
653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MC_Chunk* mc2 = *(MC_Chunk**)n2;
654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (mc1->data < mc2->data) return -1;
655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (mc1->data > mc2->data) return  1;
656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return 0;
657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void
660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browncheck_mempool_sane(MC_Mempool* mp)
661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt n_chunks, i, bad = 0;
663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static UInt tick = 0;
664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MC_Chunk **chunks = (MC_Chunk**) VG_(HT_to_array)( mp->chunks, &n_chunks );
666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!chunks)
667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;
668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_verbosity) > 1) {
670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (tick++ >= 10000)
671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       {
672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 UInt total_pools = 0, total_chunks = 0;
673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 MC_Mempool* mp2;
674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 VG_(HT_ResetIter)(MC_(mempool_list));
676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 while ( (mp2 = VG_(HT_Next)(MC_(mempool_list))) ) {
677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   total_pools++;
678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   VG_(HT_ResetIter)(mp2->chunks);
679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   while (VG_(HT_Next)(mp2->chunks)) {
680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	     total_chunks++;
681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   }
682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 }
683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)(Vg_UserMsg,
685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "Total mempools active: %d pools, %d chunks\n",
686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		      total_pools, total_chunks);
687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 tick = 0;
688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       }
689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(ssort)((void*)chunks, n_chunks, sizeof(VgHashNode*), mp_compar);
693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Sanity check; assert that the blocks are now in order */
695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < n_chunks-1; i++) {
696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (chunks[i]->data > chunks[i+1]->data) {
697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)(Vg_UserMsg,
698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "Mempool chunk %d / %d is out of order "
699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "wrt. its successor\n",
700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      i+1, n_chunks);
701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         bad = 1;
702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Sanity check -- make sure they don't overlap */
706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < n_chunks-1; i++) {
707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (chunks[i]->data + chunks[i]->szB > chunks[i+1]->data ) {
708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)(Vg_UserMsg,
709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "Mempool chunk %d / %d overlaps with its successor\n",
710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      i+1, n_chunks);
711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         bad = 1;
712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (bad) {
716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)(Vg_UserMsg,
717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                "Bad mempool (%d chunks), dumping chunks for inspection:\n",
718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                n_chunks);
719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         for (i = 0; i < n_chunks; ++i) {
720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(message)(Vg_UserMsg,
721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         "Mempool chunk %d / %d: %ld bytes "
722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         "[%lx,%lx), allocated:\n",
723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         i+1,
724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         n_chunks,
725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         chunks[i]->szB + 0UL,
726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         chunks[i]->data,
727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         chunks[i]->data + chunks[i]->szB);
728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(pp_ExeContext)(chunks[i]->where);
730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(free)(chunks);
733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid MC_(mempool_alloc)(ThreadId tid, Addr pool, Addr addr, SizeT szB)
736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MC_Mempool* mp;
738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_verbosity) > 2) {
740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(message)(Vg_UserMsg, "mempool_alloc(0x%lx, 0x%lx, %ld)\n",
741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               pool, addr, szB);
742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(get_and_pp_StackTrace) (tid, MEMPOOL_DEBUG_STACKTRACE_DEPTH);
743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mp = VG_(HT_lookup) ( MC_(mempool_list), (UWord)pool );
746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (mp == NULL) {
747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      MC_(record_illegal_mempool_error) ( tid, pool );
748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
749f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      if (MP_DETAILED_SANITY_CHECKS) check_mempool_sane(mp);
750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      MC_(new_block)(tid, addr, szB, /*ignored*/0, mp->is_zeroed,
751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     MC_AllocCustom, mp->chunks);
752f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      if (MP_DETAILED_SANITY_CHECKS) check_mempool_sane(mp);
753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid MC_(mempool_free)(Addr pool, Addr addr)
757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MC_Mempool*  mp;
759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MC_Chunk*    mc;
760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadId     tid = VG_(get_running_tid)();
761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mp = VG_(HT_lookup)(MC_(mempool_list), (UWord)pool);
763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (mp == NULL) {
764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      MC_(record_illegal_mempool_error)(tid, pool);
765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;
766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_verbosity) > 2) {
769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(message)(Vg_UserMsg, "mempool_free(0x%lx, 0x%lx)\n", pool, addr);
770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(get_and_pp_StackTrace) (tid, MEMPOOL_DEBUG_STACKTRACE_DEPTH);
771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
773f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   if (MP_DETAILED_SANITY_CHECKS) check_mempool_sane(mp);
774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mc = VG_(HT_remove)(mp->chunks, (UWord)addr);
775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (mc == NULL) {
776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      MC_(record_free_error)(tid, (Addr)addr);
777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;
778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_verbosity) > 2) {
781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(message)(Vg_UserMsg,
782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		   "mempool_free(0x%lx, 0x%lx) freed chunk of %ld bytes\n",
783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		   pool, addr, mc->szB + 0UL);
784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   die_and_free_mem ( tid, mc, mp->rzB );
787f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   if (MP_DETAILED_SANITY_CHECKS) check_mempool_sane(mp);
788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid MC_(mempool_trim)(Addr pool, Addr addr, SizeT szB)
792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MC_Mempool*  mp;
794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MC_Chunk*    mc;
795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadId     tid = VG_(get_running_tid)();
796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt         n_shadows, i;
797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VgHashNode** chunks;
798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_verbosity) > 2) {
800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(message)(Vg_UserMsg, "mempool_trim(0x%lx, 0x%lx, %ld)\n",
801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               pool, addr, szB);
802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(get_and_pp_StackTrace) (tid, MEMPOOL_DEBUG_STACKTRACE_DEPTH);
803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mp = VG_(HT_lookup)(MC_(mempool_list), (UWord)pool);
806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (mp == NULL) {
807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      MC_(record_illegal_mempool_error)(tid, pool);
808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;
809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   check_mempool_sane(mp);
812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   chunks = VG_(HT_to_array) ( mp->chunks, &n_shadows );
813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (n_shadows == 0) {
814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     tl_assert(chunks == NULL);
815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     return;
816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(chunks != NULL);
819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < n_shadows; ++i) {
820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Addr lo, hi, min, max;
822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mc = (MC_Chunk*) chunks[i];
824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lo = mc->data;
826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hi = mc->szB == 0 ? mc->data : mc->data + mc->szB - 1;
827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define EXTENT_CONTAINS(x) ((addr <= (x)) && ((x) < addr + szB))
829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (EXTENT_CONTAINS(lo) && EXTENT_CONTAINS(hi)) {
831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* The current chunk is entirely within the trim extent: keep
833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            it. */
834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else if ( (! EXTENT_CONTAINS(lo)) &&
838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (! EXTENT_CONTAINS(hi)) ) {
839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* The current chunk is entirely outside the trim extent:
841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delete it. */
842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (VG_(HT_remove)(mp->chunks, (UWord)mc->data) == NULL) {
844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            MC_(record_free_error)(tid, (Addr)mc->data);
845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(free)(chunks);
846f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root            if (MP_DETAILED_SANITY_CHECKS) check_mempool_sane(mp);
847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return;
848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         die_and_free_mem ( tid, mc, mp->rzB );
850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* The current chunk intersects the trim extent: remove,
854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            trim, and reinsert it. */
855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(EXTENT_CONTAINS(lo) ||
857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   EXTENT_CONTAINS(hi));
858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (VG_(HT_remove)(mp->chunks, (UWord)mc->data) == NULL) {
859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            MC_(record_free_error)(tid, (Addr)mc->data);
860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(free)(chunks);
861f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root            if (MP_DETAILED_SANITY_CHECKS) check_mempool_sane(mp);
862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return;
863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (mc->data < addr) {
866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           min = mc->data;
867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           lo = addr;
868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           min = addr;
870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           lo = mc->data;
871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (mc->data + szB > addr + szB) {
874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           max = mc->data + szB;
875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           hi = addr + szB;
876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           max = addr + szB;
878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           hi = mc->data + szB;
879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(min <= lo);
882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(lo < hi);
883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(hi <= max);
884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (min < lo && !EXTENT_CONTAINS(min)) {
886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           MC_(make_mem_noaccess)( min, lo - min);
887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (hi < max && !EXTENT_CONTAINS(max)) {
890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           MC_(make_mem_noaccess)( hi, max - hi );
891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mc->data = lo;
894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mc->szB = (UInt) (hi - lo);
895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(HT_add_node)( mp->chunks, mc );
896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#undef EXTENT_CONTAINS
899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   check_mempool_sane(mp);
902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(free)(chunks);
903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid MC_(move_mempool)(Addr poolA, Addr poolB)
906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MC_Mempool* mp;
908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_verbosity) > 2) {
910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(message)(Vg_UserMsg, "move_mempool(0x%lx, 0x%lx)\n", poolA, poolB);
911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(get_and_pp_StackTrace)
912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         (VG_(get_running_tid)(), MEMPOOL_DEBUG_STACKTRACE_DEPTH);
913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mp = VG_(HT_remove) ( MC_(mempool_list), (UWord)poolA );
916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (mp == NULL) {
918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ThreadId tid = VG_(get_running_tid)();
919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      MC_(record_illegal_mempool_error) ( tid, poolA );
920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;
921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mp->pool = poolB;
924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(HT_add_node)( MC_(mempool_list), mp );
925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid MC_(mempool_change)(Addr pool, Addr addrA, Addr addrB, SizeT szB)
928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MC_Mempool*  mp;
930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MC_Chunk*    mc;
931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadId     tid = VG_(get_running_tid)();
932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_verbosity) > 2) {
934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(message)(Vg_UserMsg, "mempool_change(0x%lx, 0x%lx, 0x%lx, %ld)\n",
935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   pool, addrA, addrB, szB);
936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(get_and_pp_StackTrace) (tid, MEMPOOL_DEBUG_STACKTRACE_DEPTH);
937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mp = VG_(HT_lookup)(MC_(mempool_list), (UWord)pool);
940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (mp == NULL) {
941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      MC_(record_illegal_mempool_error)(tid, pool);
942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;
943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   check_mempool_sane(mp);
946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mc = VG_(HT_remove)(mp->chunks, (UWord)addrA);
948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (mc == NULL) {
949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      MC_(record_free_error)(tid, (Addr)addrA);
950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;
951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mc->data = addrB;
954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mc->szB  = szB;
955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(HT_add_node)( mp->chunks, mc );
956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   check_mempool_sane(mp);
958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool MC_(mempool_exists)(Addr pool)
961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MC_Mempool*  mp;
963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mp = VG_(HT_lookup)(MC_(mempool_list), (UWord)pool);
965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (mp == NULL) {
966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       return False;
967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;
969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Statistics printing                                  ---*/
974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid MC_(print_malloc_stats) ( void )
977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MC_Chunk* mc;
979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SizeT     nblocks = 0;
980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ULong     nbytes  = 0;
981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_verbosity) == 0)
983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;
984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_xml))
985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;
986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Count memory still in use. */
988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(HT_ResetIter)(MC_(malloc_list));
989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while ( (mc = VG_(HT_Next)(MC_(malloc_list))) ) {
990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      nblocks++;
991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      nbytes += (ULong)mc->szB;
992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(umsg)(
995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "HEAP SUMMARY:\n"
996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "    in use at exit: %'llu bytes in %'lu blocks\n"
997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "  total heap usage: %'lu allocs, %'lu frees, %'llu bytes allocated\n"
998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "\n",
999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      nbytes, nblocks,
1000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      cmalloc_n_mallocs,
1001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      cmalloc_n_frees, cmalloc_bs_mallocd
1002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
1003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
1006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- end                                                          ---*/
1007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
1008