PROF_EVENT(71, "find_shadow_for_OLD(loop)");
a_lo = shadows[i]->data;
a_hi = ((Addr)shadows[i]->data) + shadows[i]->size;
- if (a_lo <= ptr && ptr <= a_hi)
+ if (a_lo <= ptr && ptr < a_hi)
return i;
}
return -1;
mid = (lo + hi) / 2;
a_mid_lo = shadows[mid]->data;
a_mid_hi = shadows[mid]->data + shadows[mid]->size;
+ /* Extent of block 'mid' is [a_mid_lo .. a_mid_hi).
+ Special-case zero-sized blocks - treat them as if they had
+ size 1. Not doing so causes them to not cover any address
+ range at all and so will never be identified as the target of
+ any pointer, which causes them to be incorrectly reported as
+ definitely leaked. */
+ if (shadows[mid]->size == 0)
+ a_mid_hi++;
if (ptr < a_mid_lo) {
hi = mid-1;
continue;
}
- if (ptr > a_mid_hi) {
+ if (ptr >= a_mid_hi) {
lo = mid+1;
continue;
}
- tl_assert(ptr >= a_mid_lo && ptr <= a_mid_hi);
+ tl_assert(ptr >= a_mid_lo && ptr < a_mid_hi);
retVal = mid;
break;
}
return;
tl_assert(sh_no >= 0 && sh_no < lc_n_shadows);
- tl_assert(ptr <= lc_shadows[sh_no]->data + lc_shadows[sh_no]->size);
+ tl_assert(ptr >= lc_shadows[sh_no]->data);
+ tl_assert(ptr < lc_shadows[sh_no]->data
+ + lc_shadows[sh_no]->size
+ + (lc_shadows[sh_no]->size==0 ? 1 : 0));
if (lc_markstack[sh_no].state == Unreached) {
if (0)
}
}
+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 = (MC_Chunk**) VG_(HT_to_array)( MC_(malloc_list), &n_mallocs );
+
+ if (n_mallocs == 0) {
+ tl_assert(mallocs == NULL);
+ *n_shadows = 0;
+ return NULL;
+ }
+
+ VG_(ssort)((void*)mallocs, n_mallocs,
+ sizeof(VgHashNode*), lc_compar);
+
+ malloc_chunk_holds_a_pool_chunk = VG_(calloc)( n_mallocs, sizeof(Bool) );
+
+ *n_shadows = n_mallocs;
+
+ VG_(HT_ResetIter)(MC_(mempool_list));
+ while ( (mp = VG_(HT_Next)(MC_(mempool_list))) ) {
+ VG_(HT_ResetIter)(mp->chunks);
+ while ( (mc = 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 = find_shadow_for(mc->data, mallocs, n_mallocs);
+ if (m != -1 && malloc_chunk_holds_a_pool_chunk[m] == False) {
+ tl_assert(*n_shadows > 0);
+ --(*n_shadows);
+ malloc_chunk_holds_a_pool_chunk[m] = True;
+ }
+
+ /* Possibly invalidate the malloc holding the end of this chunk. */
+ if (mc->size > 1) {
+ m = find_shadow_for(mc->data + (mc->size - 1), mallocs, n_mallocs);
+ if (m != -1 && malloc_chunk_holds_a_pool_chunk[m] == False) {
+ tl_assert(*n_shadows > 0);
+ --(*n_shadows);
+ malloc_chunk_holds_a_pool_chunk[m] = True;
+ }
+ }
+ }
+ }
+
+ tl_assert(*n_shadows > 0);
+ shadows = VG_(malloc)(sizeof(VgHashNode*) * (*n_shadows));
+ s = 0;
+
+ /* Copy the mempool chunks into the final array. */
+ VG_(HT_ResetIter)(MC_(mempool_list));
+ while ( (mp = VG_(HT_Next)(MC_(mempool_list))) ) {
+ VG_(HT_ResetIter)(mp->chunks);
+ while ( (mc = VG_(HT_Next)(mp->chunks)) ) {
+ tl_assert(s < *n_shadows);
+ shadows[s++] = mc;
+ }
+ }
+
+ /* Copy the malloc chunks into the final array. */
+ for (m = 0; m < n_mallocs; ++m) {
+ if (!malloc_chunk_holds_a_pool_chunk[m]) {
+ tl_assert(s < *n_shadows);
+ shadows[s++] = mallocs[m];
+ }
+ }
+
+ tl_assert(s == *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 the
tl_assert(mode != LC_Off);
- /* VG_(HT_to_array) allocates storage for shadows */
- lc_shadows = (MC_Chunk**)VG_(HT_to_array)( MC_(malloc_list),
- &lc_n_shadows );
+ lc_shadows = find_active_shadows(&lc_n_shadows);
/* Sort the array. */
VG_(ssort)((void*)lc_shadows, lc_n_shadows, sizeof(VgHashNode*), lc_compar);
by 0x........: main (mempool.c:148)
-100,028 (20 direct, 100,008 indirect) bytes in 1 blocks are definitely lost in loss record 2 of 3
+10 bytes in 1 blocks are definitely lost in loss record 2 of 5
+ at 0x........: allocate (mempool.c:99)
+ by 0x........: test (mempool.c:135)
+ by 0x........: main (mempool.c:148)
+
+
+10 bytes in 1 blocks are definitely lost in loss record 3 of 5
+ at 0x........: allocate (mempool.c:99)
+ by 0x........: test (mempool.c:115)
+ by 0x........: main (mempool.c:148)
+
+
+20 bytes in 1 blocks are definitely lost in loss record 4 of 5
+ at 0x........: allocate (mempool.c:99)
+ by 0x........: test (mempool.c:116)
+ by 0x........: main (mempool.c:148)
+
+
+28 (20 direct, 8 indirect) bytes in 1 blocks are definitely lost in loss record 5 of 5
at 0x........: malloc (vg_replace_malloc.c:...)
by 0x........: make_pool (mempool.c:37)
by 0x........: test (mempool.c:111)