|
From: <sv...@va...> - 2006-07-27 23:48:56
|
Author: sewardj
Date: 2006-07-28 00:48:53 +0100 (Fri, 28 Jul 2006)
New Revision: 5991
Log:
Leak checking fixes from Graydon Hoare:
- fix off by one error in binary searches
- extend leak checking functionality to memory pools
Modified:
trunk/memcheck/mc_leakcheck.c
Modified: trunk/memcheck/mc_leakcheck.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_leakcheck.c 2006-07-27 23:12:17 UTC (rev 5990)
+++ trunk/memcheck/mc_leakcheck.c 2006-07-27 23:48:53 UTC (rev 5991)
@@ -175,7 +175,7 @@
PROF_EVENT(71, "find_shadow_for_OLD(loop)");
a_lo =3D shadows[i]->data;
a_hi =3D ((Addr)shadows[i]->data) + shadows[i]->size;
- if (a_lo <=3D ptr && ptr <=3D a_hi)
+ if (a_lo <=3D ptr && ptr < a_hi)
return i;
}
return -1;
@@ -206,11 +206,11 @@
hi =3D mid-1;
continue;
}=20
- if (ptr > a_mid_hi) {
+ if (ptr >=3D a_mid_hi) {
lo =3D mid+1;
continue;
}
- tl_assert(ptr >=3D a_mid_lo && ptr <=3D a_mid_hi);
+ tl_assert(ptr >=3D a_mid_lo && ptr < a_mid_hi);
retVal =3D mid;
break;
}
@@ -345,7 +345,8 @@
return;
=20
tl_assert(sh_no >=3D 0 && sh_no < lc_n_shadows);
- tl_assert(ptr <=3D lc_shadows[sh_no]->data + lc_shadows[sh_no]->size)=
;
+ tl_assert(ptr >=3D lc_shadows[sh_no]->data);
+ tl_assert(ptr < lc_shadows[sh_no]->data + lc_shadows[sh_no]->size);
=20
if (lc_markstack[sh_no].state =3D=3D Unreached) {
if (0)
@@ -673,6 +674,107 @@
}
}
=20
+static MC_Chunk**
+find_active_shadows(UInt* n_shadows)
+{
+ /* Our goal is to construct a set of shadows that includes every
+ * mempool chunk, and every malloc region that *doesn't* contain a
+ * mempool chunk. We do this in several phases.
+ *
+ * First we collect all the malloc chunks into an array and sort it.
+ * We do this because we want to query the chunks by interior
+ * pointers, requiring binary search.
+ *
+ * Second we build an array containing a Bool for each malloc chunk,
+ * indicating whether it contains any mempools.
+ *
+ * Third we loop over the mempool tables. For each chunk in each
+ * pool, we set the entry in the Bool array corresponding to the
+ * malloc chunk containing the mempool chunk.
+ *
+ * Finally we copy the mempool chunks and the non-marked malloc
+ * chunks into a combined array of shadows, free our temporaries,
+ * and return the combined array.
+ */
+
+ MC_Mempool *mp;
+ MC_Chunk **mallocs, **shadows, *mc;
+ UInt n_mallocs, m, s;
+ Bool *malloc_chunk_holds_a_pool_chunk;
+
+ mallocs =3D (MC_Chunk**) VG_(HT_to_array)( MC_(malloc_list), &n_mallo=
cs );
+
+ if (n_mallocs =3D=3D 0) {
+ tl_assert(mallocs =3D=3D NULL);
+ *n_shadows =3D 0;
+ return NULL;
+ }
+
+ VG_(ssort)((void*)mallocs, n_mallocs,=20
+ sizeof(VgHashNode*), lc_compar);
+
+ malloc_chunk_holds_a_pool_chunk =3D VG_(calloc)( n_mallocs, sizeof(Bo=
ol) );
+
+ *n_shadows =3D n_mallocs;
+
+ VG_(HT_ResetIter)(MC_(mempool_list));
+ while ( (mp =3D VG_(HT_Next)(MC_(mempool_list))) ) {
+ VG_(HT_ResetIter)(mp->chunks);
+ while ( (mc =3D VG_(HT_Next)(mp->chunks)) ) {
+
+ /* We'll need a shadow for this chunk. */
+ ++(*n_shadows);
+
+ /* Possibly invalidate the malloc holding the beginning of this=
chunk. */
+ m =3D find_shadow_for(mc->data, mallocs, n_mallocs);
+ if (m !=3D -1 && malloc_chunk_holds_a_pool_chunk[m] =3D=3D Fals=
e) {
+ tl_assert(*n_shadows > 0);
+ --(*n_shadows);
+ malloc_chunk_holds_a_pool_chunk[m] =3D True;
+ }
+
+ /* Possibly invalidate the malloc holding the end of this chunk=
. */
+ if (mc->size > 1) {
+ m =3D find_shadow_for(mc->data + (mc->size - 1), mallocs, n_=
mallocs);
+ if (m !=3D -1 && malloc_chunk_holds_a_pool_chunk[m] =3D=3D F=
alse) {
+ tl_assert(*n_shadows > 0);
+ --(*n_shadows);
+ malloc_chunk_holds_a_pool_chunk[m] =3D True;
+ }
+ }
+ }
+ }
+
+ tl_assert(*n_shadows > 0);
+ shadows =3D VG_(malloc)(sizeof(VgHashNode*) * (*n_shadows));
+ s =3D 0;
+
+ /* Copy the mempool chunks into the final array. */
+ VG_(HT_ResetIter)(MC_(mempool_list));
+ while ( (mp =3D VG_(HT_Next)(MC_(mempool_list))) ) {
+ VG_(HT_ResetIter)(mp->chunks);
+ while ( (mc =3D VG_(HT_Next)(mp->chunks)) ) {
+ tl_assert(s < *n_shadows);
+ shadows[s++] =3D mc;
+ }
+ }
+
+ /* Copy the malloc chunks into the final array. */
+ for (m =3D 0; m < n_mallocs; ++m) {
+ if (!malloc_chunk_holds_a_pool_chunk[m]) {
+ tl_assert(s < *n_shadows);
+ shadows[s++] =3D mallocs[m];
+ }
+ }
+
+ tl_assert(s =3D=3D *n_shadows);
+ VG_(free)(mallocs);
+ VG_(free)(malloc_chunk_holds_a_pool_chunk);
+
+ return shadows;
+}
+
+
/* Top level entry point to leak detector. Call here, passing in
suitable address-validating functions (see comment at top of
scan_all_valid_memory above). These functions used to encapsulate th=
e
@@ -689,9 +791,7 @@
=20
tl_assert(mode !=3D LC_Off);
=20
- /* VG_(HT_to_array) allocates storage for shadows */
- lc_shadows =3D (MC_Chunk**)VG_(HT_to_array)( MC_(malloc_list),
- &lc_n_shadows );
+ lc_shadows =3D find_active_shadows(&lc_n_shadows);
=20
/* Sort the array. */
VG_(ssort)((void*)lc_shadows, lc_n_shadows, sizeof(VgHashNode*), lc_c=
ompar);
|