Clarify name and description/manual for meta mempool

* rename macro VALGRIND_CREATE_META_MEMPOOL
     to VALGRIND_CREATE_MEMPOOL_EXT
* abort execution if a pool is marked as auto_free but is not a meta pool
  + removed test leak-autofreepool-3.vgtest, which now aborts.
* reword/clarify valgrind.h explanations for meta pool
* similarly reword/clarify the manual



git-svn-id: svn://svn.valgrind.org/valgrind/trunk@16042
This commit is contained in:
Philippe Waroquiers 2016-10-15 12:59:04 +00:00
parent 7ac00163a3
commit 38fab04de9
7 changed files with 87 additions and 61 deletions

View File

@ -7009,21 +7009,37 @@ VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
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) \

View File

@ -2320,34 +2320,53 @@ inform Memcheck about changes to the state of a mempool:</para>
</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>

View File

@ -711,12 +711,17 @@ void MC_(create_mempool)(Addr pool, UInt rzB, Bool is_zeroed,
{
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);

View File

@ -153,13 +153,11 @@ EXTRA_DIST = \
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 \

View File

@ -1,10 +0,0 @@
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)

View File

@ -1,4 +0,0 @@
prog: leak-autofreepool
vgopts: --leak-check=full --show-possibly-lost=no --track-origins=yes
args: 3
stderr_filter: filter_allocs

View File

@ -7,7 +7,7 @@
#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
@ -64,7 +64,7 @@ static char MetaBlock[POOL_BLOCK_SIZE];
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;
@ -124,7 +124,7 @@ static void *allocate_plain_style (struct pool *p, size_t n)
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.
@ -148,13 +148,15 @@ static void set_flags ( int n )
// 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;
@ -185,7 +187,7 @@ static void set_flags ( int n )
// 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;
@ -314,9 +316,9 @@ int main( int argc, char** argv )
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,