VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CREATE_MEMPOOL, \
pool, rzB, is_zeroed, 0, 0)
-/* Create a memory pool with special flags. When the VALGRIND_MEMPOOL_AUTO_FREE
- is passed, a MEMPOOL_DELETE will auto-free all chunks (so not reported as
- leaks) for allocators that assume that destroying a pool destroys all
- objects in the pool. When VALGRIND_MEMPOOL_METAPOOL is passed, the custom
- allocator uses the pool blocks as superblocks to dole out MALLOC_LIKE blocks.
- The resulting behaviour would normally be classified as overlapping blocks,
- and cause assert-errors in valgrind.
- These 2 MEMPOOL flags can be OR-ed together into the "flags" argument.
+/* Create a memory pool with some flags specifying extended behaviour.
When flags is zero, the behaviour is identical to VALGRIND_CREATE_MEMPOOL.
+
+ The flag VALGRIND_MEMPOOL_METAPOOL specifies that the pieces of memory
+ associated with the pool using VALGRIND_MEMPOOL_ALLOC will be used
+ by the application as superblocks to dole out MALLOC_LIKE blocks using
+ VALGRIND_MALLOCLIKE_BLOCK. In other words, a meta pool is a "2 levels"
+ pool : first level is the blocks described by VALGRIND_MEMPOOL_ALLOC.
+ The second level blocks are described using VALGRIND_MALLOCLIKE_BLOCK.
+ Note that the association between the pool and the second level blocks
+ is implicit : second level blocks will be located inside first level
+ blocks. It is necessary to use the VALGRIND_MEMPOOL_METAPOOL flag
+ for such 2 levels pools, as otherwise valgrind will detect overlapping
+ memory blocks, and will abort execution (e.g. during leak search).
+
+ Such a meta pool can also be marked as an 'auto free' pool using the flag
+ VALGRIND_MEMPOOL_AUTO_FREE, which must be OR-ed together with the
+ VALGRIND_MEMPOOL_METAPOOL. For an 'auto free' pool, VALGRIND_MEMPOOL_FREE
+ will automatically free the second level blocks that are contained
+ inside the first level block freed with VALGRIND_MEMPOOL_FREE.
+ In other words, calling VALGRIND_MEMPOOL_FREE will cause implicit calls
+ to VALGRIND_FREELIKE_BLOCK for all the second level blocks included
+ in the first level block.
+ Note: it is an error to use the VALGRIND_MEMPOOL_AUTO_FREE flag
+ without the VALGRIND_MEMPOOL_METAPOOL flag.
*/
#define VALGRIND_MEMPOOL_AUTO_FREE 1
#define VALGRIND_MEMPOOL_METAPOOL 2
-#define VALGRIND_CREATE_META_MEMPOOL(pool, rzB, is_zeroed, flags) \
- VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CREATE_MEMPOOL, \
- pool, rzB, is_zeroed, flags, 0)
+#define VALGRIND_CREATE_MEMPOOL_EXT(pool, rzB, is_zeroed, flags) \
+ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CREATE_MEMPOOL, \
+ pool, rzB, is_zeroed, flags, 0)
/* Destroy a memory pool. */
#define VALGRIND_DESTROY_MEMPOOL(pool) \
</listitem>
<listitem>
+ <!-- Note: the below is mostly a copy of valgrind.h. Keep in sync! -->
<para>
- <varname>VALGRIND_CREATE_META_MEMPOOL(pool, rzB, is_zeroed, flags)</varname>:
- This does the same as <varname>VALGRIND_CREATE_MEMPOOL</varname>,
- but allows you to specify two seldom-used options for custom
- allocators (or-ed together) in the <varname>flags</varname> argument:</para>
+ <varname>VALGRIND_CREATE_MEMPOOL_EXT(pool, rzB, is_zeroed, flags)</varname>:
+ Create a memory pool with some flags (that can
+ be OR-ed together) specifying extended behaviour. When flags is
+ zero, the behaviour is identical to
+ <varname>VALGRIND_CREATE_MEMPOOL</varname>.</para>
<itemizedlist>
<listitem>
- <para>
- <varname>VALGRIND_MEMPOOL_AUTO_FREE</varname>.
- This indicates that items allocated from this
- memory pool are automatically freed when
- <varname>VALGRIND_MEMPOOL_FREE</varname>
- is used on a block. This allows a custom allocator to delete
- (part of) a memory pool without explicitly deleting all allocated
- items. Without this option, such an action will report all items
- in the pool as memory leaks.
+ <para> The flag <varname>VALGRIND_MEMPOOL_METAPOOL</varname>
+ specifies that the pieces of memory associated with the pool
+ using <varname>VALGRIND_MEMPOOL_ALLOC</varname> will be used
+ by the application as superblocks to dole out MALLOC_LIKE
+ blocks using <varname>VALGRIND_MALLOCLIKE_BLOCK</varname>.
+ In other words, a meta pool is a "2 levels" pool : first
+ level is the blocks described
+ by <varname>VALGRIND_MEMPOOL_ALLOC</varname>. The second
+ level blocks are described
+ using <varname>VALGRIND_MALLOCLIKE_BLOCK</varname>. Note
+ that the association between the pool and the second level
+ blocks is implicit : second level blocks will be located
+ inside first level blocks. It is necessary to use
+ the <varname>VALGRIND_MEMPOOL_METAPOOL</varname> flag for
+ such 2 levels pools, as otherwise valgrind will detect
+ overlapping memory blocks, and will abort execution
+ (e.g. during leak search).
</para>
</listitem>
<listitem>
<para>
- <varname>VALGRIND_MEMPOOL_METAPOOL</varname>.
- This indicates that memory that has been
- marked as being allocated with
- <varname>VALGRIND_MALLOCLIKE_BLOCK</varname> is used
- by a custom allocator to pass out memory to an application (again
- marked with <varname>VALGRIND_MALLOCLIKE_BLOCK</varname>).
- Without this option, such overlapping memory blocks may trigger
- a fatal error message in memcheck.
+ <varname>VALGRIND_MEMPOOL_AUTO_FREE</varname>. Such a meta
+ pool can also be marked as an 'auto free' pool using the
+ flag <varname>VALGRIND_MEMPOOL_AUTO_FREE</varname>, which
+ must be OR-ed together with
+ the <varname>VALGRIND_MEMPOOL_METAPOOL</varname>. For an
+ 'auto free' pool, <varname>VALGRIND_MEMPOOL_FREE</varname>
+ will automatically free the second level blocks that are
+ contained inside the first level block freed
+ with <varname>VALGRIND_MEMPOOL_FREE</varname>. In other
+ words, calling <varname>VALGRIND_MEMPOOL_FREE</varname> will
+ cause implicit calls
+ to <varname>VALGRIND_FREELIKE_BLOCK</varname> for all the
+ second level blocks included in the first level block.
+ Note: it is an error to use
+ the <varname>VALGRIND_MEMPOOL_AUTO_FREE</varname> flag
+ without the
+ <varname>VALGRIND_MEMPOOL_METAPOOL</varname> flag.
</para>
</listitem>
</itemizedlist>
{
MC_Mempool* mp;
- if (VG_(clo_verbosity) > 2) {
+ if (VG_(clo_verbosity) > 2 || (auto_free && !metapool)) {
VG_(message)(Vg_UserMsg,
- "create_mempool(0x%lx, rzB=%u, zeroed=%d, autofree=%d, metapool=%d)\n",
- pool, rzB, is_zeroed, auto_free, metapool);
+ "create_mempool(0x%lx, rzB=%u, zeroed=%d,"
+ " autofree=%d, metapool=%d)\n",
+ pool, rzB, is_zeroed,
+ auto_free, metapool);
VG_(get_and_pp_StackTrace)
(VG_(get_running_tid)(), MEMPOOL_DEBUG_STACKTRACE_DEPTH);
+ if (auto_free && !metapool)
+ VG_(tool_panic)("Inappropriate use of mempool:"
+ " an auto free pool must be a meta pool. Aborting\n");
}
mp = VG_(HT_lookup)(MC_(mempool_list), (UWord)pool);
leak-pool-0.vgtest leak-pool-0.stderr.exp \
leak-pool-1.vgtest leak-pool-1.stderr.exp \
leak-pool-2.vgtest leak-pool-2.stderr.exp \
- leak-pool-3.vgtest leak-pool-3.stderr.exp \
leak-pool-4.vgtest leak-pool-4.stderr.exp \
leak-pool-5.vgtest leak-pool-5.stderr.exp \
leak-autofreepool-0.vgtest leak-autofreepool-0.stderr.exp \
leak-autofreepool-1.vgtest leak-autofreepool-1.stderr.exp \
leak-autofreepool-2.vgtest leak-autofreepool-2.stderr.exp \
- leak-autofreepool-3.vgtest leak-autofreepool-3.stderr.exp \
leak-autofreepool-4.vgtest leak-autofreepool-4.stderr.exp \
leak-autofreepool-5.vgtest leak-autofreepool-5.stderr.exp \
leak-autofreepool-6.vgtest leak-autofreepool-6.stderr.exp \
+++ /dev/null
-
-
-HEAP SUMMARY:
- in use at exit: ... bytes in ... blocks
- total heap usage: ... allocs, ... frees, ... bytes allocated
-
-All heap blocks were freed -- no leaks are possible
-
-For counts of detected and suppressed errors, rerun with: -v
-ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
+++ /dev/null
-prog: leak-autofreepool
-vgopts: --leak-check=full --show-possibly-lost=no --track-origins=yes
-args: 3
-stderr_filter: filter_allocs
#include "../memcheck.h"
-// Test VALGRIND_CREATE_META_MEMPOOL features, the VALGRIND_MEMPOOL_METAPOOL and
+// Test VALGRIND_CREATE_MEMPOOL_EXT features, the VALGRIND_MEMPOOL_METAPOOL and
// VALGRIND_MEMPOOL_AUTO_FREE flags.
// Also show that without these, having a custom allocator that:
// - Allocates a MEMPOOL
void create_meta_pool (void)
{
- VALGRIND_CREATE_META_MEMPOOL(MetaPool, 0, 0, MetaPoolFlags);
+ VALGRIND_CREATE_MEMPOOL_EXT(MetaPool, 0, 0, MetaPoolFlags);
VALGRIND_MEMPOOL_ALLOC(MetaPool, MetaBlock, POOL_BLOCK_SIZE);
MetaPool->buf = (uint8_t *) MetaBlock;
static void set_flags ( int n )
{
switch (n) {
- // Case 0: No special flags. VALGRIND_CREATE_META_MEMPOOL is same as
+ // Case 0: No special flags. VALGRIND_CREATE_MEMPOOL_EXT is same as
// VALGRIND_CREATE_MEMPOOL.
// When mempools are destroyed, the METAPOOL leaks because auto-free is
// missing. Must show 2*N (20) leaks.
// Same as before, but now the MALLOCLIKE blocks are auto-freed.
// Must show 0 leaks.
case 2:
- MetaPoolFlags = VALGRIND_MEMPOOL_AUTO_FREE | VALGRIND_MEMPOOL_METAPOOL;
+ MetaPoolFlags = VALGRIND_MEMPOOL_METAPOOL | VALGRIND_MEMPOOL_AUTO_FREE;
CleanupBeforeExit = 1;
break;
- case 3:
- // Just auto-free, with cleanup. The cleanup removes the overlapping
- // blocks, so this is the same as case 2: No leaks, no problems.
+ case 3: // Note: this is incorrect behaviour, and aborts valgrind.
+ // (so it is not exercised during regression testing).
+ // Just auto-free, not marked with meta pool flag.
+ // This is an error, and will cause valgrind to abort when the pool
+ // is created.
MetaPoolFlags = VALGRIND_MEMPOOL_AUTO_FREE;
CleanupBeforeExit = 1;
break;
// already done above) is by allocating lots of other chunks that are
// NOT part of the pool so the MC_Alloc lists contain other stuff.
// That will make the iterator find stuff AND skip stuff.
- MetaPoolFlags = VALGRIND_MEMPOOL_AUTO_FREE | VALGRIND_MEMPOOL_METAPOOL;
+ MetaPoolFlags = VALGRIND_MEMPOOL_METAPOOL | VALGRIND_MEMPOOL_AUTO_FREE;
CleanupBeforeExit = 1;
GenerateNoise = 1;
break;
pool_block_size = nr_elts * sizeof(struct cell) + sizeof(uint8_t) + 1;
// Create perf meta pool
- VALGRIND_CREATE_META_MEMPOOL
+ VALGRIND_CREATE_MEMPOOL_EXT
(&perf_meta_pool, 0, 0,
- VALGRIND_MEMPOOL_AUTO_FREE | VALGRIND_MEMPOOL_METAPOOL);
+ VALGRIND_MEMPOOL_METAPOOL | VALGRIND_MEMPOOL_AUTO_FREE);
perf_meta_block = malloc(pool_block_size);
VALGRIND_MEMPOOL_ALLOC(&perf_meta_pool, perf_meta_block,