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