Home | History | Annotate | Download | only in memcheck
      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-2012 Julian Seward
     12       jseward (at) 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 ... */
     53 static SizeT cmalloc_n_mallocs  = 0;
     54 static SizeT cmalloc_n_frees    = 0;
     55 static 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 
     66 SizeT MC_(Malloc_Redzone_SzB) = -10000000; // If used before set, should BOMB
     67 
     68 /* Record malloc'd blocks. */
     69 VgHashTable MC_(malloc_list) = NULL;
     70 
     71 /* Memory pools: a hash table of MC_Mempools.  Search key is
     72    MC_Mempool::pool. */
     73 VgHashTable MC_(mempool_list) = NULL;
     74 
     75 /* Pool allocator for MC_Chunk. */
     76 PoolAlloc *MC_(chunk_poolalloc) = NULL;
     77 static
     78 MC_Chunk* create_MC_Chunk ( ExeContext* ec, Addr p, SizeT szB,
     79                             MC_AllocKind kind);
     80 static inline
     81 void 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. */
     94 static MC_Chunk* freed_list_start[2]  = {NULL, NULL};
     95 static 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. */
     99 static 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). */
    134 static 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 
    171 MC_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. */
    189 static
    190 MC_Chunk* create_MC_Chunk ( ExeContext* ec, 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    mc->where     = ec;
    198 
    199    /* Each time a new MC_Chunk is created, release oldest blocks
    200       if the free list volume is exceeded. */
    201    if (VG_(free_queue_volume) > MC_(clo_freelist_vol))
    202       release_oldest_block();
    203 
    204    /* Paranoia ... ensure the MC_Chunk is off-limits to the client, so
    205       the mc->data field isn't visible to the leak checker.  If memory
    206       management is working correctly, any pointer returned by VG_(malloc)
    207       should be noaccess as far as the client is concerned. */
    208    if (!MC_(check_mem_is_noaccess)( (Addr)mc, sizeof(MC_Chunk), NULL )) {
    209       VG_(tool_panic)("create_MC_Chunk: shadow area is accessible");
    210    }
    211    return mc;
    212 }
    213 
    214 static inline
    215 void delete_MC_Chunk (MC_Chunk* mc)
    216 {
    217    VG_(freeEltPA) (MC_(chunk_poolalloc), mc);
    218 }
    219 
    220 /*------------------------------------------------------------*/
    221 /*--- client_malloc(), etc                                 ---*/
    222 /*------------------------------------------------------------*/
    223 
    224 // XXX: should make this a proper error (bug #79311).
    225 static Bool complain_about_silly_args(SizeT sizeB, Char* fn)
    226 {
    227    // Cast to a signed type to catch any unexpectedly negative args.  We're
    228    // assuming here that the size asked for is not greater than 2^31 bytes
    229    // (for 32-bit platforms) or 2^63 bytes (for 64-bit platforms).
    230    if ((SSizeT)sizeB < 0) {
    231       if (!VG_(clo_xml))
    232          VG_(message)(Vg_UserMsg, "Warning: silly arg (%ld) to %s()\n",
    233                       (SSizeT)sizeB, fn );
    234       return True;
    235    }
    236    return False;
    237 }
    238 
    239 static Bool complain_about_silly_args2(SizeT n, SizeT sizeB)
    240 {
    241    if ((SSizeT)n < 0 || (SSizeT)sizeB < 0) {
    242       if (!VG_(clo_xml))
    243          VG_(message)(Vg_UserMsg,
    244                       "Warning: silly args (%ld,%ld) to calloc()\n",
    245                       (SSizeT)n, (SSizeT)sizeB);
    246       return True;
    247    }
    248    return False;
    249 }
    250 
    251 /* Allocate memory and note change in memory available */
    252 void* MC_(new_block) ( ThreadId tid,
    253                        Addr p, SizeT szB, SizeT alignB,
    254                        Bool is_zeroed, MC_AllocKind kind, VgHashTable table)
    255 {
    256    ExeContext* ec;
    257 
    258    // Allocate and zero if necessary
    259    if (p) {
    260       tl_assert(MC_AllocCustom == kind);
    261    } else {
    262       tl_assert(MC_AllocCustom != kind);
    263       p = (Addr)VG_(cli_malloc)( alignB, szB );
    264       if (!p) {
    265          return NULL;
    266       }
    267       if (is_zeroed) {
    268          VG_(memset)((void*)p, 0, szB);
    269       } else
    270       if (MC_(clo_malloc_fill) != -1) {
    271          tl_assert(MC_(clo_malloc_fill) >= 0x00 && MC_(clo_malloc_fill) <= 0xFF);
    272          VG_(memset)((void*)p, MC_(clo_malloc_fill), szB);
    273       }
    274    }
    275 
    276    // Only update stats if allocation succeeded.
    277    cmalloc_n_mallocs ++;
    278    cmalloc_bs_mallocd += (ULong)szB;
    279 
    280    ec = VG_(record_ExeContext)(tid, 0/*first_ip_delta*/);
    281    tl_assert(ec);
    282 
    283    VG_(HT_add_node)( table, create_MC_Chunk(ec, p, szB, kind) );
    284 
    285    if (is_zeroed)
    286       MC_(make_mem_defined)( p, szB );
    287    else {
    288       UInt ecu = VG_(get_ECU_from_ExeContext)(ec);
    289       tl_assert(VG_(is_plausible_ECU)(ecu));
    290       MC_(make_mem_undefined_w_otag)( p, szB, ecu | MC_OKIND_HEAP );
    291    }
    292 
    293    return (void*)p;
    294 }
    295 
    296 void* MC_(malloc) ( ThreadId tid, SizeT n )
    297 {
    298    if (complain_about_silly_args(n, "malloc")) {
    299       return NULL;
    300    } else {
    301       return MC_(new_block) ( tid, 0, n, VG_(clo_alignment),
    302          /*is_zeroed*/False, MC_AllocMalloc, MC_(malloc_list));
    303    }
    304 }
    305 
    306 void* MC_(__builtin_new) ( ThreadId tid, SizeT n )
    307 {
    308    if (complain_about_silly_args(n, "__builtin_new")) {
    309       return NULL;
    310    } else {
    311       return MC_(new_block) ( tid, 0, n, VG_(clo_alignment),
    312          /*is_zeroed*/False, MC_AllocNew, MC_(malloc_list));
    313    }
    314 }
    315 
    316 void* MC_(__builtin_vec_new) ( ThreadId tid, SizeT n )
    317 {
    318    if (complain_about_silly_args(n, "__builtin_vec_new")) {
    319       return NULL;
    320    } else {
    321       return MC_(new_block) ( tid, 0, n, VG_(clo_alignment),
    322          /*is_zeroed*/False, MC_AllocNewVec, MC_(malloc_list));
    323    }
    324 }
    325 
    326 void* MC_(memalign) ( ThreadId tid, SizeT alignB, SizeT n )
    327 {
    328    if (complain_about_silly_args(n, "memalign")) {
    329       return NULL;
    330    } else {
    331       return MC_(new_block) ( tid, 0, n, alignB,
    332          /*is_zeroed*/False, MC_AllocMalloc, MC_(malloc_list));
    333    }
    334 }
    335 
    336 void* MC_(calloc) ( ThreadId tid, SizeT nmemb, SizeT size1 )
    337 {
    338    if (complain_about_silly_args2(nmemb, size1)) {
    339       return NULL;
    340    } else {
    341       return MC_(new_block) ( tid, 0, nmemb*size1, VG_(clo_alignment),
    342          /*is_zeroed*/True, MC_AllocMalloc, MC_(malloc_list));
    343    }
    344 }
    345 
    346 static
    347 void die_and_free_mem ( ThreadId tid, MC_Chunk* mc, SizeT rzB )
    348 {
    349    /* Note: we do not free fill the custom allocs produced
    350       by MEMPOOL or by MALLOC/FREELIKE_BLOCK requests. */
    351    if (MC_(clo_free_fill) != -1 && MC_AllocCustom != mc->allockind ) {
    352       tl_assert(MC_(clo_free_fill) >= 0x00 && MC_(clo_free_fill) <= 0xFF);
    353       VG_(memset)((void*)mc->data, MC_(clo_free_fill), mc->szB);
    354    }
    355 
    356    /* Note: make redzones noaccess again -- just in case user made them
    357       accessible with a client request... */
    358    MC_(make_mem_noaccess)( mc->data-rzB, mc->szB + 2*rzB );
    359 
    360    /* Record where freed */
    361    mc->where = VG_(record_ExeContext) ( tid, 0/*first_ip_delta*/ );
    362    /* Put it out of harm's way for a while */
    363    add_to_freed_queue ( mc );
    364    /* If the free list volume is bigger than MC_(clo_freelist_vol),
    365       we wait till the next block allocation to release blocks.
    366       This increase the chance to discover dangling pointer usage,
    367       even for big blocks being freed by the client. */
    368 }
    369 
    370 void MC_(handle_free) ( ThreadId tid, Addr p, UInt rzB, MC_AllocKind kind )
    371 {
    372    MC_Chunk* mc;
    373 
    374    cmalloc_n_frees++;
    375 
    376    mc = VG_(HT_remove) ( MC_(malloc_list), (UWord)p );
    377    if (mc == NULL) {
    378       MC_(record_free_error) ( tid, p );
    379    } else {
    380       /* check if it is a matching free() / delete / delete [] */
    381       if (kind != mc->allockind) {
    382          tl_assert(p == mc->data);
    383          MC_(record_freemismatch_error) ( tid, mc );
    384       }
    385       die_and_free_mem ( tid, mc, rzB );
    386    }
    387 }
    388 
    389 void MC_(free) ( ThreadId tid, void* p )
    390 {
    391    MC_(handle_free)(
    392       tid, (Addr)p, MC_(Malloc_Redzone_SzB), MC_AllocMalloc );
    393 }
    394 
    395 void MC_(__builtin_delete) ( ThreadId tid, void* p )
    396 {
    397    MC_(handle_free)(
    398       tid, (Addr)p, MC_(Malloc_Redzone_SzB), MC_AllocNew);
    399 }
    400 
    401 void MC_(__builtin_vec_delete) ( ThreadId tid, void* p )
    402 {
    403    MC_(handle_free)(
    404       tid, (Addr)p, MC_(Malloc_Redzone_SzB), MC_AllocNewVec);
    405 }
    406 
    407 void* MC_(realloc) ( ThreadId tid, void* p_old, SizeT new_szB )
    408 {
    409    MC_Chunk* mc;
    410    void*     p_new;
    411    SizeT     old_szB;
    412 
    413    if (complain_about_silly_args(new_szB, "realloc"))
    414       return NULL;
    415 
    416    cmalloc_n_frees ++;
    417    cmalloc_n_mallocs ++;
    418    cmalloc_bs_mallocd += (ULong)new_szB;
    419 
    420    /* Remove the old block */
    421    mc = VG_(HT_remove) ( MC_(malloc_list), (UWord)p_old );
    422    if (mc == NULL) {
    423       MC_(record_free_error) ( tid, (Addr)p_old );
    424       /* We return to the program regardless. */
    425       return NULL;
    426    }
    427 
    428    /* check if its a matching free() / delete / delete [] */
    429    if (MC_AllocMalloc != mc->allockind) {
    430       /* can not realloc a range that was allocated with new or new [] */
    431       tl_assert((Addr)p_old == mc->data);
    432       MC_(record_freemismatch_error) ( tid, mc );
    433       /* but keep going anyway */
    434    }
    435 
    436    old_szB = mc->szB;
    437 
    438    /* In all cases, even when the new size is smaller or unchanged, we
    439       reallocate and copy the contents, and make the old block
    440       inaccessible.  This is so as to guarantee to catch all cases of
    441       accesses via the old address after reallocation, regardless of
    442       the change in size.  (Of course the ability to detect accesses
    443       to the old block also depends on the size of the freed blocks
    444       queue). */
    445 
    446    if (new_szB <= old_szB) {
    447       /* new size is smaller or the same */
    448       Addr a_new;
    449       /* Get new memory */
    450       a_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_szB);
    451 
    452       if (a_new) {
    453          ExeContext* ec;
    454 
    455          ec = VG_(record_ExeContext)(tid, 0/*first_ip_delta*/);
    456          tl_assert(ec);
    457 
    458          /* Retained part is copied, red zones set as normal */
    459          MC_(make_mem_noaccess)( a_new-MC_(Malloc_Redzone_SzB),
    460                                  MC_(Malloc_Redzone_SzB) );
    461          MC_(copy_address_range_state) ( (Addr)p_old, a_new, new_szB );
    462          MC_(make_mem_noaccess)        ( a_new+new_szB, MC_(Malloc_Redzone_SzB));
    463 
    464          /* Copy from old to new */
    465          VG_(memcpy)((void*)a_new, p_old, new_szB);
    466 
    467          /* Possibly fill freed area with specified junk. */
    468          if (MC_(clo_free_fill) != -1) {
    469             tl_assert(MC_(clo_free_fill) >= 0x00 && MC_(clo_free_fill) <= 0xFF);
    470             VG_(memset)((void*)p_old, MC_(clo_free_fill), old_szB);
    471          }
    472 
    473          /* Free old memory */
    474          /* Nb: we have to allocate a new MC_Chunk for the new memory rather
    475             than recycling the old one, so that any erroneous accesses to the
    476             old memory are reported. */
    477          die_and_free_mem ( tid, mc, MC_(Malloc_Redzone_SzB) );
    478 
    479          // Allocate a new chunk.
    480          mc = create_MC_Chunk( ec, a_new, new_szB, MC_AllocMalloc );
    481       }
    482 
    483       p_new = (void*)a_new;
    484 
    485    } else {
    486       /* new size is bigger */
    487       Addr a_new;
    488       tl_assert(old_szB < new_szB);
    489       /* Get new memory */
    490       a_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_szB);
    491 
    492       if (a_new) {
    493          UInt        ecu;
    494          ExeContext* ec;
    495 
    496          ec = VG_(record_ExeContext)(tid, 0/*first_ip_delta*/);
    497          tl_assert(ec);
    498          ecu = VG_(get_ECU_from_ExeContext)(ec);
    499          tl_assert(VG_(is_plausible_ECU)(ecu));
    500 
    501          /* First half kept and copied, second half new, red zones as normal */
    502          MC_(make_mem_noaccess)( a_new-MC_(Malloc_Redzone_SzB),
    503                                  MC_(Malloc_Redzone_SzB) );
    504          MC_(copy_address_range_state) ( (Addr)p_old, a_new, mc->szB );
    505          MC_(make_mem_undefined_w_otag)( a_new+mc->szB, new_szB-mc->szB,
    506                                                         ecu | MC_OKIND_HEAP );
    507          MC_(make_mem_noaccess)        ( a_new+new_szB, MC_(Malloc_Redzone_SzB) );
    508 
    509          /* Possibly fill new area with specified junk */
    510          if (MC_(clo_malloc_fill) != -1) {
    511             tl_assert(MC_(clo_malloc_fill) >= 0x00
    512                       && MC_(clo_malloc_fill) <= 0xFF);
    513             VG_(memset)((void*)(a_new+old_szB), MC_(clo_malloc_fill),
    514                                                 new_szB-old_szB);
    515          }
    516 
    517          /* Copy from old to new */
    518          VG_(memcpy)((void*)a_new, p_old, mc->szB);
    519 
    520          /* Possibly fill freed area with specified junk. */
    521          if (MC_(clo_free_fill) != -1) {
    522             tl_assert(MC_(clo_free_fill) >= 0x00 && MC_(clo_free_fill) <= 0xFF);
    523             VG_(memset)((void*)p_old, MC_(clo_free_fill), old_szB);
    524          }
    525 
    526          /* Free old memory */
    527          /* Nb: we have to allocate a new MC_Chunk for the new memory rather
    528             than recycling the old one, so that any erroneous accesses to the
    529             old memory are reported. */
    530          die_and_free_mem ( tid, mc, MC_(Malloc_Redzone_SzB) );
    531 
    532          // Allocate a new chunk.
    533          mc = create_MC_Chunk( ec, a_new, new_szB, MC_AllocMalloc );
    534       }
    535 
    536       p_new = (void*)a_new;
    537    }
    538 
    539    // Now insert the new mc (with a possibly new 'data' field) into
    540    // malloc_list.  If this realloc() did not increase the memory size, we
    541    // will have removed and then re-added mc unnecessarily.  But that's ok
    542    // because shrinking a block with realloc() is (presumably) much rarer
    543    // than growing it, and this way simplifies the growing case.
    544    VG_(HT_add_node)( MC_(malloc_list), mc );
    545 
    546    return p_new;
    547 }
    548 
    549 SizeT MC_(malloc_usable_size) ( ThreadId tid, void* p )
    550 {
    551    MC_Chunk* mc = VG_(HT_lookup) ( MC_(malloc_list), (UWord)p );
    552 
    553    // There may be slop, but pretend there isn't because only the asked-for
    554    // area will be marked as addressable.
    555    return ( mc ? mc->szB : 0 );
    556 }
    557 
    558 /* This handles the in place resize of a block, as performed by the
    559    VALGRIND_RESIZEINPLACE_BLOCK client request.  It is unrelated to,
    560    and not used for, handling of the normal libc realloc()
    561    function. */
    562 void MC_(handle_resizeInPlace)(ThreadId tid, Addr p,
    563                                SizeT oldSizeB, SizeT newSizeB, SizeT rzB)
    564 {
    565    MC_Chunk* mc = VG_(HT_lookup) ( MC_(malloc_list), (UWord)p );
    566    if (!mc || mc->szB != oldSizeB || newSizeB == 0) {
    567       /* Reject if: p is not found, or oldSizeB is wrong,
    568          or new block would be empty. */
    569       MC_(record_free_error) ( tid, p );
    570       return;
    571    }
    572 
    573    if (oldSizeB == newSizeB)
    574       return;
    575 
    576    mc->szB = newSizeB;
    577    if (newSizeB < oldSizeB) {
    578       MC_(make_mem_noaccess)( p + newSizeB, oldSizeB - newSizeB + rzB );
    579    } else {
    580       ExeContext* ec  = VG_(record_ExeContext)(tid, 0/*first_ip_delta*/);
    581       UInt        ecu = VG_(get_ECU_from_ExeContext)(ec);
    582       MC_(make_mem_undefined_w_otag)( p + oldSizeB, newSizeB - oldSizeB,
    583                                       ecu | MC_OKIND_HEAP );
    584       if (rzB > 0)
    585          MC_(make_mem_noaccess)( p + newSizeB, rzB );
    586    }
    587 }
    588 
    589 
    590 /*------------------------------------------------------------*/
    591 /*--- Memory pool stuff.                                   ---*/
    592 /*------------------------------------------------------------*/
    593 
    594 /* Set to 1 for intensive sanity checking.  Is very expensive though
    595    and should not be used in production scenarios.  See #255966. */
    596 #define MP_DETAILED_SANITY_CHECKS 0
    597 
    598 static void check_mempool_sane(MC_Mempool* mp); /*forward*/
    599 
    600 
    601 void MC_(create_mempool)(Addr pool, UInt rzB, Bool is_zeroed)
    602 {
    603    MC_Mempool* mp;
    604 
    605    if (VG_(clo_verbosity) > 2) {
    606       VG_(message)(Vg_UserMsg, "create_mempool(0x%lx, %d, %d)\n",
    607                                pool, rzB, is_zeroed);
    608       VG_(get_and_pp_StackTrace)
    609          (VG_(get_running_tid)(), MEMPOOL_DEBUG_STACKTRACE_DEPTH);
    610    }
    611 
    612    mp = VG_(HT_lookup)(MC_(mempool_list), (UWord)pool);
    613    if (mp != NULL) {
    614      VG_(tool_panic)("MC_(create_mempool): duplicate pool creation");
    615    }
    616 
    617    mp = VG_(malloc)("mc.cm.1", sizeof(MC_Mempool));
    618    mp->pool       = pool;
    619    mp->rzB        = rzB;
    620    mp->is_zeroed  = is_zeroed;
    621    mp->chunks     = VG_(HT_construct)( "MC_(create_mempool)" );
    622    check_mempool_sane(mp);
    623 
    624    /* Paranoia ... ensure this area is off-limits to the client, so
    625       the mp->data field isn't visible to the leak checker.  If memory
    626       management is working correctly, anything pointer returned by
    627       VG_(malloc) should be noaccess as far as the client is
    628       concerned. */
    629    if (!MC_(check_mem_is_noaccess)( (Addr)mp, sizeof(MC_Mempool), NULL )) {
    630       VG_(tool_panic)("MC_(create_mempool): shadow area is accessible");
    631    }
    632 
    633    VG_(HT_add_node)( MC_(mempool_list), mp );
    634 }
    635 
    636 void MC_(destroy_mempool)(Addr pool)
    637 {
    638    MC_Chunk*   mc;
    639    MC_Mempool* mp;
    640 
    641    if (VG_(clo_verbosity) > 2) {
    642       VG_(message)(Vg_UserMsg, "destroy_mempool(0x%lx)\n", pool);
    643       VG_(get_and_pp_StackTrace)
    644          (VG_(get_running_tid)(), MEMPOOL_DEBUG_STACKTRACE_DEPTH);
    645    }
    646 
    647    mp = VG_(HT_remove) ( MC_(mempool_list), (UWord)pool );
    648 
    649    if (mp == NULL) {
    650       ThreadId tid = VG_(get_running_tid)();
    651       MC_(record_illegal_mempool_error) ( tid, pool );
    652       return;
    653    }
    654    check_mempool_sane(mp);
    655 
    656    // Clean up the chunks, one by one
    657    VG_(HT_ResetIter)(mp->chunks);
    658    while ( (mc = VG_(HT_Next)(mp->chunks)) ) {
    659       /* Note: make redzones noaccess again -- just in case user made them
    660          accessible with a client request... */
    661       MC_(make_mem_noaccess)(mc->data-mp->rzB, mc->szB + 2*mp->rzB );
    662    }
    663    // Destroy the chunk table
    664    VG_(HT_destruct)(mp->chunks, (void (*)(void *))delete_MC_Chunk);
    665 
    666    VG_(free)(mp);
    667 }
    668 
    669 static Int
    670 mp_compar(void* n1, void* n2)
    671 {
    672    MC_Chunk* mc1 = *(MC_Chunk**)n1;
    673    MC_Chunk* mc2 = *(MC_Chunk**)n2;
    674    if (mc1->data < mc2->data) return -1;
    675    if (mc1->data > mc2->data) return  1;
    676    return 0;
    677 }
    678 
    679 static void
    680 check_mempool_sane(MC_Mempool* mp)
    681 {
    682    UInt n_chunks, i, bad = 0;
    683    static UInt tick = 0;
    684 
    685    MC_Chunk **chunks = (MC_Chunk**) VG_(HT_to_array)( mp->chunks, &n_chunks );
    686    if (!chunks)
    687       return;
    688 
    689    if (VG_(clo_verbosity) > 1) {
    690      if (tick++ >= 10000)
    691        {
    692 	 UInt total_pools = 0, total_chunks = 0;
    693 	 MC_Mempool* mp2;
    694 
    695 	 VG_(HT_ResetIter)(MC_(mempool_list));
    696 	 while ( (mp2 = VG_(HT_Next)(MC_(mempool_list))) ) {
    697 	   total_pools++;
    698 	   VG_(HT_ResetIter)(mp2->chunks);
    699 	   while (VG_(HT_Next)(mp2->chunks)) {
    700 	     total_chunks++;
    701 	   }
    702 	 }
    703 
    704          VG_(message)(Vg_UserMsg,
    705                       "Total mempools active: %d pools, %d chunks\n",
    706 		      total_pools, total_chunks);
    707 	 tick = 0;
    708        }
    709    }
    710 
    711 
    712    VG_(ssort)((void*)chunks, n_chunks, sizeof(VgHashNode*), mp_compar);
    713 
    714    /* Sanity check; assert that the blocks are now in order */
    715    for (i = 0; i < n_chunks-1; i++) {
    716       if (chunks[i]->data > chunks[i+1]->data) {
    717          VG_(message)(Vg_UserMsg,
    718                       "Mempool chunk %d / %d is out of order "
    719                       "wrt. its successor\n",
    720                       i+1, n_chunks);
    721          bad = 1;
    722       }
    723    }
    724 
    725    /* Sanity check -- make sure they don't overlap */
    726    for (i = 0; i < n_chunks-1; i++) {
    727       if (chunks[i]->data + chunks[i]->szB > chunks[i+1]->data ) {
    728          VG_(message)(Vg_UserMsg,
    729                       "Mempool chunk %d / %d overlaps with its successor\n",
    730                       i+1, n_chunks);
    731          bad = 1;
    732       }
    733    }
    734 
    735    if (bad) {
    736          VG_(message)(Vg_UserMsg,
    737                 "Bad mempool (%d chunks), dumping chunks for inspection:\n",
    738                 n_chunks);
    739          for (i = 0; i < n_chunks; ++i) {
    740             VG_(message)(Vg_UserMsg,
    741                          "Mempool chunk %d / %d: %ld bytes "
    742                          "[%lx,%lx), allocated:\n",
    743                          i+1,
    744                          n_chunks,
    745                          chunks[i]->szB + 0UL,
    746                          chunks[i]->data,
    747                          chunks[i]->data + chunks[i]->szB);
    748 
    749             VG_(pp_ExeContext)(chunks[i]->where);
    750          }
    751    }
    752    VG_(free)(chunks);
    753 }
    754 
    755 void MC_(mempool_alloc)(ThreadId tid, Addr pool, Addr addr, SizeT szB)
    756 {
    757    MC_Mempool* mp;
    758 
    759    if (VG_(clo_verbosity) > 2) {
    760       VG_(message)(Vg_UserMsg, "mempool_alloc(0x%lx, 0x%lx, %ld)\n",
    761                                pool, addr, szB);
    762       VG_(get_and_pp_StackTrace) (tid, MEMPOOL_DEBUG_STACKTRACE_DEPTH);
    763    }
    764 
    765    mp = VG_(HT_lookup) ( MC_(mempool_list), (UWord)pool );
    766    if (mp == NULL) {
    767       MC_(record_illegal_mempool_error) ( tid, pool );
    768    } else {
    769       if (MP_DETAILED_SANITY_CHECKS) check_mempool_sane(mp);
    770       MC_(new_block)(tid, addr, szB, /*ignored*/0, mp->is_zeroed,
    771                      MC_AllocCustom, mp->chunks);
    772       if (mp->rzB > 0) {
    773          // This is not needed if the user application has properly
    774          // marked the superblock noaccess when defining the mempool.
    775          // We however still mark the redzones noaccess to still catch
    776          // some bugs if user forgot.
    777          MC_(make_mem_noaccess) ( addr - mp->rzB, mp->rzB);
    778          MC_(make_mem_noaccess) ( addr + szB, mp->rzB);
    779       }
    780       if (MP_DETAILED_SANITY_CHECKS) check_mempool_sane(mp);
    781    }
    782 }
    783 
    784 void MC_(mempool_free)(Addr pool, Addr addr)
    785 {
    786    MC_Mempool*  mp;
    787    MC_Chunk*    mc;
    788    ThreadId     tid = VG_(get_running_tid)();
    789 
    790    mp = VG_(HT_lookup)(MC_(mempool_list), (UWord)pool);
    791    if (mp == NULL) {
    792       MC_(record_illegal_mempool_error)(tid, pool);
    793       return;
    794    }
    795 
    796    if (VG_(clo_verbosity) > 2) {
    797       VG_(message)(Vg_UserMsg, "mempool_free(0x%lx, 0x%lx)\n", pool, addr);
    798       VG_(get_and_pp_StackTrace) (tid, MEMPOOL_DEBUG_STACKTRACE_DEPTH);
    799    }
    800 
    801    if (MP_DETAILED_SANITY_CHECKS) check_mempool_sane(mp);
    802    mc = VG_(HT_remove)(mp->chunks, (UWord)addr);
    803    if (mc == NULL) {
    804       MC_(record_free_error)(tid, (Addr)addr);
    805       return;
    806    }
    807 
    808    if (VG_(clo_verbosity) > 2) {
    809       VG_(message)(Vg_UserMsg,
    810 		   "mempool_free(0x%lx, 0x%lx) freed chunk of %ld bytes\n",
    811 		   pool, addr, mc->szB + 0UL);
    812    }
    813 
    814    die_and_free_mem ( tid, mc, mp->rzB );
    815    if (MP_DETAILED_SANITY_CHECKS) check_mempool_sane(mp);
    816 }
    817 
    818 
    819 void MC_(mempool_trim)(Addr pool, Addr addr, SizeT szB)
    820 {
    821    MC_Mempool*  mp;
    822    MC_Chunk*    mc;
    823    ThreadId     tid = VG_(get_running_tid)();
    824    UInt         n_shadows, i;
    825    VgHashNode** chunks;
    826 
    827    if (VG_(clo_verbosity) > 2) {
    828       VG_(message)(Vg_UserMsg, "mempool_trim(0x%lx, 0x%lx, %ld)\n",
    829                                pool, addr, szB);
    830       VG_(get_and_pp_StackTrace) (tid, MEMPOOL_DEBUG_STACKTRACE_DEPTH);
    831    }
    832 
    833    mp = VG_(HT_lookup)(MC_(mempool_list), (UWord)pool);
    834    if (mp == NULL) {
    835       MC_(record_illegal_mempool_error)(tid, pool);
    836       return;
    837    }
    838 
    839    check_mempool_sane(mp);
    840    chunks = VG_(HT_to_array) ( mp->chunks, &n_shadows );
    841    if (n_shadows == 0) {
    842      tl_assert(chunks == NULL);
    843      return;
    844    }
    845 
    846    tl_assert(chunks != NULL);
    847    for (i = 0; i < n_shadows; ++i) {
    848 
    849       Addr lo, hi, min, max;
    850 
    851       mc = (MC_Chunk*) chunks[i];
    852 
    853       lo = mc->data;
    854       hi = mc->szB == 0 ? mc->data : mc->data + mc->szB - 1;
    855 
    856 #define EXTENT_CONTAINS(x) ((addr <= (x)) && ((x) < addr + szB))
    857 
    858       if (EXTENT_CONTAINS(lo) && EXTENT_CONTAINS(hi)) {
    859 
    860          /* The current chunk is entirely within the trim extent: keep
    861             it. */
    862 
    863          continue;
    864 
    865       } else if ( (! EXTENT_CONTAINS(lo)) &&
    866                   (! EXTENT_CONTAINS(hi)) ) {
    867 
    868          /* The current chunk is entirely outside the trim extent:
    869             delete it. */
    870 
    871          if (VG_(HT_remove)(mp->chunks, (UWord)mc->data) == NULL) {
    872             MC_(record_free_error)(tid, (Addr)mc->data);
    873             VG_(free)(chunks);
    874             if (MP_DETAILED_SANITY_CHECKS) check_mempool_sane(mp);
    875             return;
    876          }
    877          die_and_free_mem ( tid, mc, mp->rzB );
    878 
    879       } else {
    880 
    881          /* The current chunk intersects the trim extent: remove,
    882             trim, and reinsert it. */
    883 
    884          tl_assert(EXTENT_CONTAINS(lo) ||
    885                    EXTENT_CONTAINS(hi));
    886          if (VG_(HT_remove)(mp->chunks, (UWord)mc->data) == NULL) {
    887             MC_(record_free_error)(tid, (Addr)mc->data);
    888             VG_(free)(chunks);
    889             if (MP_DETAILED_SANITY_CHECKS) check_mempool_sane(mp);
    890             return;
    891          }
    892 
    893          if (mc->data < addr) {
    894            min = mc->data;
    895            lo = addr;
    896          } else {
    897            min = addr;
    898            lo = mc->data;
    899          }
    900 
    901          if (mc->data + szB > addr + szB) {
    902            max = mc->data + szB;
    903            hi = addr + szB;
    904          } else {
    905            max = addr + szB;
    906            hi = mc->data + szB;
    907          }
    908 
    909          tl_assert(min <= lo);
    910          tl_assert(lo < hi);
    911          tl_assert(hi <= max);
    912 
    913          if (min < lo && !EXTENT_CONTAINS(min)) {
    914            MC_(make_mem_noaccess)( min, lo - min);
    915          }
    916 
    917          if (hi < max && !EXTENT_CONTAINS(max)) {
    918            MC_(make_mem_noaccess)( hi, max - hi );
    919          }
    920 
    921          mc->data = lo;
    922          mc->szB = (UInt) (hi - lo);
    923          VG_(HT_add_node)( mp->chunks, mc );
    924       }
    925 
    926 #undef EXTENT_CONTAINS
    927 
    928    }
    929    check_mempool_sane(mp);
    930    VG_(free)(chunks);
    931 }
    932 
    933 void MC_(move_mempool)(Addr poolA, Addr poolB)
    934 {
    935    MC_Mempool* mp;
    936 
    937    if (VG_(clo_verbosity) > 2) {
    938       VG_(message)(Vg_UserMsg, "move_mempool(0x%lx, 0x%lx)\n", poolA, poolB);
    939       VG_(get_and_pp_StackTrace)
    940          (VG_(get_running_tid)(), MEMPOOL_DEBUG_STACKTRACE_DEPTH);
    941    }
    942 
    943    mp = VG_(HT_remove) ( MC_(mempool_list), (UWord)poolA );
    944 
    945    if (mp == NULL) {
    946       ThreadId tid = VG_(get_running_tid)();
    947       MC_(record_illegal_mempool_error) ( tid, poolA );
    948       return;
    949    }
    950 
    951    mp->pool = poolB;
    952    VG_(HT_add_node)( MC_(mempool_list), mp );
    953 }
    954 
    955 void MC_(mempool_change)(Addr pool, Addr addrA, Addr addrB, SizeT szB)
    956 {
    957    MC_Mempool*  mp;
    958    MC_Chunk*    mc;
    959    ThreadId     tid = VG_(get_running_tid)();
    960 
    961    if (VG_(clo_verbosity) > 2) {
    962       VG_(message)(Vg_UserMsg, "mempool_change(0x%lx, 0x%lx, 0x%lx, %ld)\n",
    963                    pool, addrA, addrB, szB);
    964       VG_(get_and_pp_StackTrace) (tid, MEMPOOL_DEBUG_STACKTRACE_DEPTH);
    965    }
    966 
    967    mp = VG_(HT_lookup)(MC_(mempool_list), (UWord)pool);
    968    if (mp == NULL) {
    969       MC_(record_illegal_mempool_error)(tid, pool);
    970       return;
    971    }
    972 
    973    check_mempool_sane(mp);
    974 
    975    mc = VG_(HT_remove)(mp->chunks, (UWord)addrA);
    976    if (mc == NULL) {
    977       MC_(record_free_error)(tid, (Addr)addrA);
    978       return;
    979    }
    980 
    981    mc->data = addrB;
    982    mc->szB  = szB;
    983    VG_(HT_add_node)( mp->chunks, mc );
    984 
    985    check_mempool_sane(mp);
    986 }
    987 
    988 Bool MC_(mempool_exists)(Addr pool)
    989 {
    990    MC_Mempool*  mp;
    991 
    992    mp = VG_(HT_lookup)(MC_(mempool_list), (UWord)pool);
    993    if (mp == NULL) {
    994        return False;
    995    }
    996    return True;
    997 }
    998 
    999 
   1000 /*------------------------------------------------------------*/
   1001 /*--- Statistics printing                                  ---*/
   1002 /*------------------------------------------------------------*/
   1003 
   1004 void MC_(print_malloc_stats) ( void )
   1005 {
   1006    MC_Chunk* mc;
   1007    SizeT     nblocks = 0;
   1008    ULong     nbytes  = 0;
   1009 
   1010    if (VG_(clo_verbosity) == 0)
   1011       return;
   1012    if (VG_(clo_xml))
   1013       return;
   1014 
   1015    /* Count memory still in use. */
   1016    VG_(HT_ResetIter)(MC_(malloc_list));
   1017    while ( (mc = VG_(HT_Next)(MC_(malloc_list))) ) {
   1018       nblocks++;
   1019       nbytes += (ULong)mc->szB;
   1020    }
   1021 
   1022    VG_(umsg)(
   1023       "HEAP SUMMARY:\n"
   1024       "    in use at exit: %'llu bytes in %'lu blocks\n"
   1025       "  total heap usage: %'lu allocs, %'lu frees, %'llu bytes allocated\n"
   1026       "\n",
   1027       nbytes, nblocks,
   1028       cmalloc_n_mallocs,
   1029       cmalloc_n_frees, cmalloc_bs_mallocd
   1030    );
   1031 }
   1032 
   1033 SizeT MC_(get_cmalloc_n_frees) ( void )
   1034 {
   1035    return cmalloc_n_frees;
   1036 }
   1037 
   1038 
   1039 /*--------------------------------------------------------------------*/
   1040 /*--- end                                                          ---*/
   1041 /*--------------------------------------------------------------------*/
   1042