|
From: <sv...@va...> - 2006-10-05 17:59:28
|
Author: sewardj
Date: 2006-10-05 18:59:23 +0100 (Thu, 05 Oct 2006)
New Revision: 6197
Log:
A memory pool update from Graydon Hoare.
Here's an update to the mempool move / change client requests and sanity=20
checking. The following changes are present:
- Added one more (hopefully last) client request, a predicate to
test whether a mempool anchor address is currently tracked.
It turns out mozilla's arena-using code is sufficiently inconsistent
in its assumptions that it's very difficult to phrase the valgrind
client-request annotations without this request. Namely: sometime
arena-init and arena-free operations are assumed to be idempotent.
- Fixed a very rapid tool-memory leak in the mempool sanity check
routine. The previous version of the patch I posted would use all
memory even on my Very Beefy Test Machine within ~15 minutes of
browsing with firefox.
- Added a little logging code to print the counts of pools and chunks
active every ~10000 sanity checks, when running with -v.
Modified:
trunk/include/valgrind.h
trunk/memcheck/mc_include.h
trunk/memcheck/mc_main.c
trunk/memcheck/mc_malloc_wrappers.c
Modified: trunk/include/valgrind.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/include/valgrind.h 2006-10-05 17:56:14 UTC (rev 6196)
+++ trunk/include/valgrind.h 2006-10-05 17:59:23 UTC (rev 6197)
@@ -2289,6 +2289,9 @@
VG_USERREQ__MEMPOOL_ALLOC =3D 0x1305,
VG_USERREQ__MEMPOOL_FREE =3D 0x1306,
VG_USERREQ__MEMPOOL_TRIM =3D 0x1307,
+ VG_USERREQ__MOVE_MEMPOOL =3D 0x1308,
+ VG_USERREQ__MEMPOOL_CHANGE =3D 0x1309,
+ VG_USERREQ__MEMPOOL_EXISTS =3D 0x130a,
=20
/* Allow printfs to valgrind log. */
VG_USERREQ__PRINTF =3D 0x1401,
@@ -2513,6 +2516,31 @@
pool, addr, size, 0, 0); \
}
=20
+/* Resize and/or move a piece associated with a memory pool. */
+#define VALGRIND_MOVE_MEMPOOL(poolA, poolB) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__MOVE_MEMPOOL, \
+ poolA, poolB, 0, 0, 0); \
+ }
+
+/* Resize and/or move a piece associated with a memory pool. */
+#define VALGRIND_MEMPOOL_CHANGE(pool, addrA, addrB, size) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__MEMPOOL_CHANGE, \
+ pool, addrA, addrB, size, 0); \
+ }
+
+/* Return 1 if a mempool exists, else 0. */
+#define VALGRIND_MEMPOOL_EXISTS(pool) \
+ ({unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__MEMPOOL_EXISTS, \
+ pool, 0, 0, 0, 0); \
+ _qzz_res; \
+ })
+
/* Mark a piece of memory as being a stack. Returns a stack id. */
#define VALGRIND_STACK_REGISTER(start, end) \
({unsigned int _qzz_res; \
Modified: trunk/memcheck/mc_include.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/memcheck/mc_include.h 2006-10-05 17:56:14 UTC (rev 6196)
+++ trunk/memcheck/mc_include.h 2006-10-05 17:59:23 UTC (rev 6197)
@@ -87,6 +87,9 @@
Addr addr, SizeT size );
extern void MC_(mempool_free) ( Addr pool, Addr addr );
extern void MC_(mempool_trim) ( Addr pool, Addr addr, SizeT size );
+extern void MC_(move_mempool) ( Addr poolA, Addr poolB );
+extern void MC_(mempool_change) ( Addr pool, Addr addrA, Addr addrB, Si=
zeT size );
+extern Bool MC_(mempool_exists) ( Addr pool );
=20
extern MC_Chunk* MC_(get_freed_list_head)( void );
=20
Modified: trunk/memcheck/mc_main.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/memcheck/mc_main.c 2006-10-05 17:56:14 UTC (rev 6196)
+++ trunk/memcheck/mc_main.c 2006-10-05 17:59:23 UTC (rev 6197)
@@ -4064,7 +4064,10 @@
&& VG_USERREQ__DESTROY_MEMPOOL !=3D arg[0]
&& VG_USERREQ__MEMPOOL_ALLOC !=3D arg[0]
&& VG_USERREQ__MEMPOOL_FREE !=3D arg[0]
- && VG_USERREQ__MEMPOOL_TRIM !=3D arg[0])
+ && VG_USERREQ__MEMPOOL_TRIM !=3D arg[0]
+ && VG_USERREQ__MOVE_MEMPOOL !=3D arg[0]
+ && VG_USERREQ__MEMPOOL_CHANGE !=3D arg[0]
+ && VG_USERREQ__MEMPOOL_EXISTS !=3D arg[0])
return False;
=20
switch (arg[0]) {
@@ -4239,6 +4242,32 @@
return True;
}
=20
+ case VG_USERREQ__MOVE_MEMPOOL: {
+ Addr poolA =3D (Addr)arg[1];
+ Addr poolB =3D (Addr)arg[2];
+
+ MC_(move_mempool) ( poolA, poolB );
+ return True;
+ }
+
+ case VG_USERREQ__MEMPOOL_CHANGE: {
+ Addr pool =3D (Addr)arg[1];
+ Addr addrA =3D (Addr)arg[2];
+ Addr addrB =3D (Addr)arg[3];
+ UInt size =3D arg[4];
+
+ MC_(mempool_change) ( pool, addrA, addrB, size );
+ return True;
+ }
+
+ case VG_USERREQ__MEMPOOL_EXISTS: {
+ Addr pool =3D (Addr)arg[1];
+
+ *ret =3D (UWord) MC_(mempool_exists) ( pool );
+ return True;
+ }
+
+
default:
VG_(message)(Vg_UserMsg,=20
"Warning: unknown memcheck client request code %ll=
x",
Modified: trunk/memcheck/mc_malloc_wrappers.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/memcheck/mc_malloc_wrappers.c 2006-10-05 17:56:14 UTC (rev 6196=
)
+++ trunk/memcheck/mc_malloc_wrappers.c 2006-10-05 17:59:23 UTC (rev 6197=
)
@@ -41,6 +41,7 @@
#include "pub_tool_replacemalloc.h"
#include "pub_tool_threadstate.h"
#include "pub_tool_tooliface.h" // Needed for mc_include.h
+#include "pub_tool_stacktrace.h" // For VG_(get_and_pp_StackTrace)
=20
#include "mc_include.h"
=20
@@ -53,7 +54,11 @@
static SizeT cmalloc_n_frees =3D 0;
static SizeT cmalloc_bs_mallocd =3D 0;
=20
+/* For debug printing to do with mempools: what stack trace
+ depth to show. */
+#define MEMPOOL_DEBUG_STACKTRACE_DEPTH 16
=20
+
/*------------------------------------------------------------*/
/*--- Tracking malloc'd and free'd blocks ---*/
/*------------------------------------------------------------*/
@@ -392,7 +397,21 @@
=20
void MC_(create_mempool)(Addr pool, UInt rzB, Bool is_zeroed)
{
- MC_Mempool* mp =3D VG_(malloc)(sizeof(MC_Mempool));
+ MC_Mempool* mp;
+
+ if (VG_(clo_verbosity) > 2) {
+ VG_(message)(Vg_UserMsg, "create_mempool(%p, %d, %d)",=20
+ pool, rzB, is_zeroed);
+ VG_(get_and_pp_StackTrace)
+ (VG_(get_running_tid)(), MEMPOOL_DEBUG_STACKTRACE_DEPTH);
+ }
+
+ mp =3D VG_(HT_lookup)(MC_(mempool_list), (UWord)pool);
+ if (mp !=3D NULL) {
+ VG_(tool_panic)("MC_(create_mempool): duplicate pool creation");
+ }
+ =20
+ mp =3D VG_(malloc)(sizeof(MC_Mempool));
mp->pool =3D pool;
mp->rzB =3D rzB;
mp->is_zeroed =3D is_zeroed;
@@ -415,6 +434,12 @@
MC_Chunk* mc;
MC_Mempool* mp;
=20
+ if (VG_(clo_verbosity) > 2) {
+ VG_(message)(Vg_UserMsg, "destroy_mempool(%p)", pool);
+ VG_(get_and_pp_StackTrace)
+ (VG_(get_running_tid)(), MEMPOOL_DEBUG_STACKTRACE_DEPTH);
+ }
+
mp =3D VG_(HT_remove) ( MC_(mempool_list), (UWord)pool );
=20
if (mp =3D=3D NULL) {
@@ -436,15 +461,106 @@
VG_(free)(mp);
}
=20
+static Int=20
+mp_compar(void* n1, void* n2)
+{
+ MC_Chunk* mc1 =3D *(MC_Chunk**)n1;
+ MC_Chunk* mc2 =3D *(MC_Chunk**)n2;
+ return (mc1->data < mc2->data ? -1 : 1);
+}
+
+static void=20
+check_mempool_sane(MC_Mempool* mp)
+{
+ UInt n_chunks, i, bad =3D 0; =20
+ static UInt tick =3D 0;
+
+ MC_Chunk **chunks =3D (MC_Chunk**) VG_(HT_to_array)( mp->chunks, &n_c=
hunks );
+ if (!chunks)
+ return;
+
+ if (VG_(clo_verbosity) > 1) {
+ if (tick++ >=3D 10000)
+ {
+ UInt total_pools =3D 0, total_chunks =3D 0;
+ MC_Mempool* mp2;
+ =20
+ VG_(HT_ResetIter)(MC_(mempool_list));
+ while ( (mp2 =3D VG_(HT_Next)(MC_(mempool_list))) ) {
+ total_pools++;
+ VG_(HT_ResetIter)(mp2->chunks);
+ while (VG_(HT_Next)(mp2->chunks)) {
+ total_chunks++;
+ }
+ }
+ =20
+ VG_(message)(Vg_UserMsg,=20
+ "Total mempools active: %d pools, %d chunks\n",=20
+ total_pools, total_chunks);
+ tick =3D 0;
+ }
+ }
+
+
+ VG_(ssort)((void*)chunks, n_chunks, sizeof(VgHashNode*), mp_compar);
+ =20
+ /* Sanity check; assert that the blocks are now in order */
+ for (i =3D 0; i < n_chunks-1; i++) {
+ if (chunks[i]->data > chunks[i+1]->data) {
+ VG_(message)(Vg_UserMsg,=20
+ "Mempool chunk %d / %d is out of order "
+ "wrt. its successor",=20
+ i+1, n_chunks);
+ bad =3D 1;
+ }
+ }
+ =20
+ /* Sanity check -- make sure they don't overlap */
+ for (i =3D 0; i < n_chunks-1; i++) {
+ if (chunks[i]->data + chunks[i]->size > chunks[i+1]->data ) {
+ VG_(message)(Vg_UserMsg,=20
+ "Mempool chunk %d / %d overlaps with its successor=
",=20
+ i+1, n_chunks);
+ bad =3D 1;
+ }
+ }
+
+ if (bad) {
+ VG_(message)(Vg_UserMsg,=20
+ "Bad mempool (%d chunks), dumping chunks for inspection:=
",
+ n_chunks);
+ for (i =3D 0; i < n_chunks; ++i) {
+ VG_(message)(Vg_UserMsg,=20
+ "Mempool chunk %d / %d: %d bytes [%x,%x), alloc=
ated:",
+ i+1,=20
+ n_chunks,=20
+ chunks[i]->size,=20
+ chunks[i]->data,=20
+ chunks[i]->data + chunks[i]->size);
+
+ VG_(pp_ExeContext)(chunks[i]->where);
+ }
+ }
+ VG_(free)(chunks);
+}
+
void MC_(mempool_alloc)(ThreadId tid, Addr pool, Addr addr, SizeT size)
{
- MC_Mempool* mp =3D VG_(HT_lookup) ( MC_(mempool_list), (UWord)pool );
+ MC_Mempool* mp;
=20
+ if (VG_(clo_verbosity) > 2) { =20
+ VG_(message)(Vg_UserMsg, "mempool_alloc(%p, %p, %d)", pool, addr, =
size);
+ VG_(get_and_pp_StackTrace) (tid, MEMPOOL_DEBUG_STACKTRACE_DEPTH);
+ }
+
+ mp =3D VG_(HT_lookup) ( MC_(mempool_list), (UWord)pool );
if (mp =3D=3D NULL) {
MC_(record_illegal_mempool_error) ( tid, pool );
} else {
+ check_mempool_sane(mp);
MC_(new_block)(tid, addr, size, /*ignored*/0, mp->rzB, mp->is_zero=
ed,
MC_AllocCustom, mp->chunks);
+ check_mempool_sane(mp);
}
}
=20
@@ -460,13 +576,26 @@
return;
}
=20
+ if (VG_(clo_verbosity) > 2) {
+ VG_(message)(Vg_UserMsg, "mempool_free(%p, %p)", pool, addr);
+ VG_(get_and_pp_StackTrace) (tid, MEMPOOL_DEBUG_STACKTRACE_DEPTH);
+ }
+
+ check_mempool_sane(mp);
mc =3D VG_(HT_remove)(mp->chunks, (UWord)addr);
if (mc =3D=3D NULL) {
MC_(record_free_error)(tid, (Addr)addr);
return;
}
=20
+ if (VG_(clo_verbosity) > 2) {
+ VG_(message)(Vg_UserMsg,=20
+ "mempool_free(%p, %p) freed chunk of %d bytes",=20
+ pool, addr, mc->size);
+ }
+
die_and_free_mem ( tid, mc, mp->rzB );
+ check_mempool_sane(mp);
}
=20
=20
@@ -478,12 +607,18 @@
UInt n_shadows, i;
VgHashNode** chunks;
=20
+ if (VG_(clo_verbosity) > 2) {
+ VG_(message)(Vg_UserMsg, "mempool_trim(%p, %p, %d)", pool, addr, s=
ize);
+ VG_(get_and_pp_StackTrace) (tid, MEMPOOL_DEBUG_STACKTRACE_DEPTH);
+ }
+
mp =3D VG_(HT_lookup)(MC_(mempool_list), (UWord)pool);
if (mp =3D=3D NULL) {
MC_(record_illegal_mempool_error)(tid, pool);
return;
}
=20
+ check_mempool_sane(mp);
chunks =3D VG_(HT_to_array) ( mp->chunks, &n_shadows );
if (n_shadows =3D=3D 0) {
tl_assert(chunks =3D=3D NULL);
@@ -493,7 +628,7 @@
tl_assert(chunks !=3D NULL);
for (i =3D 0; i < n_shadows; ++i) {
=20
- Addr lo, hi;
+ Addr lo, hi, min, max;
=20
mc =3D (MC_Chunk*) chunks[i];
=20
@@ -518,6 +653,7 @@
if (VG_(HT_remove)(mp->chunks, (UWord)mc->data) =3D=3D NULL) {
MC_(record_free_error)(tid, (Addr)mc->data);
VG_(free)(chunks);
+ check_mempool_sane(mp);
return;
}
die_and_free_mem ( tid, mc, mp->rzB ); =20
@@ -532,13 +668,38 @@
if (VG_(HT_remove)(mp->chunks, (UWord)mc->data) =3D=3D NULL) {
MC_(record_free_error)(tid, (Addr)mc->data);
VG_(free)(chunks);
+ check_mempool_sane(mp);
return;
}
=20
- lo =3D mc->data > addr ? mc->data : addr;
- hi =3D mc->data + mc->size < addr + size ? mc->data + mc->size =
: addr + size;
+ if (mc->data < addr) {
+ min =3D mc->data;
+ lo =3D addr;
+ } else {
+ min =3D addr;
+ lo =3D mc->data;
+ }
=20
+ if (mc->data + size > addr + size) {
+ max =3D mc->data + size;
+ hi =3D addr + size;
+ } else {
+ max =3D addr + size;
+ hi =3D mc->data + size;
+ }
+
+ tl_assert(min <=3D lo);
tl_assert(lo < hi);
+ tl_assert(hi <=3D max);
+
+ if (min < lo && !EXTENT_CONTAINS(min)) {
+ MC_(make_mem_noaccess)( min, lo - min);
+ }
+
+ if (hi < max && !EXTENT_CONTAINS(max)) {
+ MC_(make_mem_noaccess)( hi, max - hi );
+ }
+
mc->data =3D lo;
mc->size =3D (UInt) (hi - lo);
VG_(HT_add_node)( mp->chunks, mc ); =20
@@ -547,9 +708,77 @@
#undef EXTENT_CONTAINS
=20
}
+ check_mempool_sane(mp);
VG_(free)(chunks);
}
=20
+void MC_(move_mempool)(Addr poolA, Addr poolB)
+{
+ MC_Mempool* mp;
+
+ if (VG_(clo_verbosity) > 2) {
+ VG_(message)(Vg_UserMsg, "move_mempool(%p, %p)", poolA, poolB);
+ VG_(get_and_pp_StackTrace)
+ (VG_(get_running_tid)(), MEMPOOL_DEBUG_STACKTRACE_DEPTH);
+ }
+
+ mp =3D VG_(HT_remove) ( MC_(mempool_list), (UWord)poolA );
+
+ if (mp =3D=3D NULL) {
+ ThreadId tid =3D VG_(get_running_tid)();
+ MC_(record_illegal_mempool_error) ( tid, poolA );
+ return;
+ }
+
+ mp->pool =3D poolB;
+ VG_(HT_add_node)( MC_(mempool_list), mp );
+}
+
+void MC_(mempool_change)(Addr pool, Addr addrA, Addr addrB, SizeT size)
+{
+ MC_Mempool* mp;
+ MC_Chunk* mc;
+ ThreadId tid =3D VG_(get_running_tid)();
+
+ if (VG_(clo_verbosity) > 2) {
+ VG_(message)(Vg_UserMsg, "mempool_change(%p, %p, %p, %d)",=20
+ pool, addrA, addrB, size);
+ VG_(get_and_pp_StackTrace) (tid, MEMPOOL_DEBUG_STACKTRACE_DEPTH);
+ }
+
+ mp =3D VG_(HT_lookup)(MC_(mempool_list), (UWord)pool);
+ if (mp =3D=3D NULL) {
+ MC_(record_illegal_mempool_error)(tid, pool);
+ return;
+ }
+
+ check_mempool_sane(mp);
+
+ mc =3D VG_(HT_remove)(mp->chunks, (UWord)addrA);
+ if (mc =3D=3D NULL) {
+ MC_(record_free_error)(tid, (Addr)addrA);
+ return;
+ }
+
+ mc->data =3D addrB;
+ mc->size =3D size;
+ VG_(HT_add_node)( mp->chunks, mc );
+
+ check_mempool_sane(mp);
+}
+
+Bool MC_(mempool_exists)(Addr pool)
+{
+ MC_Mempool* mp;
+
+ mp =3D VG_(HT_lookup)(MC_(mempool_list), (UWord)pool);
+ if (mp =3D=3D NULL) {
+ return False;
+ }
+ return True;
+}
+
+
/*------------------------------------------------------------*/
/*--- Statistics printing ---*/
/*------------------------------------------------------------*/
|