fix assertions around an empty theap in _mi_page_update_sample_countdown
diff --git a/src/alloc/page.c b/src/alloc/page.c index f344cc7..9431a6f 100644 --- a/src/alloc/page.c +++ b/src/alloc/page.c
@@ -177,13 +177,13 @@ #endif #if MI_STATS -// Merge stats from the page into the corresponding theap (or heap if theap==NULL). -static void mi_theap_page_merge_stats(mi_theap_t* theap, const mi_page_t* page, size_t alloc_count, size_t free_count ) { +// Merge stats from the page into the corresponding theap (or heap if theapx==NULL). +static void mi_theap_page_merge_stats(mi_theap_t* theapx, const mi_page_t* page, size_t alloc_count, size_t free_count ) { // get heap (as the theap might be NULL) mi_heap_t* const heap = mi_page_heap(page); - mi_assert_internal(theap == NULL || (theap->tld != NULL && _mi_thread_id() == theap->tld->thread_id)); - mi_theapx_stat_counter_increase(heap,theap,pages_stat_updates,1); - mi_theapx_stat_counter_increase(heap,theap,pages_stat_update_count, alloc_count + free_count); + mi_assert_internal(theapx == NULL || (theapx->tld != NULL && _mi_thread_id() == theapx->tld->thread_id)); + mi_theapx_stat_counter_increase(heap,theapx,pages_stat_updates,1); + mi_theapx_stat_counter_increase(heap,theapx,pages_stat_update_count, alloc_count + free_count); // allocation sizes const size_t bsize = mi_page_usable_block_size(page); @@ -198,45 +198,45 @@ // adjust stats const size_t bin = _mi_bin(bsize); if (alloc_count > 0) { - mi_theapx_stat_counter_increase(heap, theap, malloc_count, alloc_count); - mi_theapx_stat_increase(heap, theap, allocated, allocated); - mi_theapx_stat_increase(heap, theap, malloc_bins[bin], alloc_count); - if (bin==MI_BIN_HUGE) { mi_theapx_stat_increase(heap,theap,malloc_huge,allocated); } // separate so we have a count and total + mi_theapx_stat_counter_increase(heap, theapx, malloc_count, alloc_count); + mi_theapx_stat_increase(heap, theapx, allocated, allocated); + mi_theapx_stat_increase(heap, theapx, malloc_bins[bin], alloc_count); + if (bin==MI_BIN_HUGE) { mi_theapx_stat_increase(heap,theapx,malloc_huge,allocated); } // separate so we have a count and total #if MI_STATS==1 // use coarse total requested bytes - mi_theapx_stat_counter_increase(heap, theap, malloc_requested, requested); + mi_theapx_stat_counter_increase(heap, theapx, malloc_requested, requested); #endif // deprecated if (bin!=MI_BIN_HUGE) { - mi_theapx_stat_counter_increase(heap, theap, malloc_normal_count, alloc_count); - mi_theapx_stat_increase(heap, theap, malloc_normal, allocated); + mi_theapx_stat_counter_increase(heap, theapx, malloc_normal_count, alloc_count); + mi_theapx_stat_increase(heap, theapx, malloc_normal, allocated); } else { - mi_theapx_stat_counter_increase(heap, theap, malloc_huge_count, alloc_count); + mi_theapx_stat_counter_increase(heap, theapx, malloc_huge_count, alloc_count); } } if (free_count > 0) { - mi_theapx_stat_counter_increase(heap, theap, free_count, free_count); - mi_theapx_stat_counter_increase(heap, theap, freed, freed); - mi_theapx_stat_decrease(heap, theap, allocated, freed); - mi_theapx_stat_decrease(heap, theap, malloc_bins[bin], free_count); - if (bin==MI_BIN_HUGE) { mi_theapx_stat_decrease(heap, theap, malloc_huge, freed); } + mi_theapx_stat_counter_increase(heap, theapx, free_count, free_count); + mi_theapx_stat_counter_increase(heap, theapx, freed, freed); + mi_theapx_stat_decrease(heap, theapx, allocated, freed); + mi_theapx_stat_decrease(heap, theapx, malloc_bins[bin], free_count); + if (bin==MI_BIN_HUGE) { mi_theapx_stat_decrease(heap, theapx, malloc_huge, freed); } // deprecated - if (bin!=MI_BIN_HUGE) { mi_theapx_stat_decrease(heap, theap, malloc_normal, freed); } + if (bin!=MI_BIN_HUGE) { mi_theapx_stat_decrease(heap, theapx, malloc_normal, freed); } } // merge the theap stats into the heap once N bytes were allocated or freed since the last merge - if (theap != NULL) { + if (theapx != NULL) { const size_t threshold = mi_option_get_size(mi_option_stats_merge_threshold); - const int64_t churn = theap->stats.allocated.total + theap->stats.freed.total; + const int64_t churn = theapx->stats.allocated.total + theapx->stats.freed.total; if (threshold > 0 && churn >= (int64_t)threshold) { - _mi_theap_merge_stats(theap); + _mi_theap_merge_stats(theapx); } } } -// Update stats for a page (and sample countdown) -static void mi_theap_page_update_stats(mi_theap_t* theap, mi_page_t* page) { +// Update stats for a page (and sample countdown). Can be called with a NULL `theapx` +static void mi_theap_page_update_stats(mi_theap_t* theapx, mi_page_t* page) { mi_assert_internal(mi_page_alloc_count(page) + mi_page_last_used(page) >= mi_page_used(page)); mi_assert_internal(mi_page_alloc_count(page) >= mi_page_last_alloc(page)); @@ -249,7 +249,7 @@ const size_t free_count = last_used + alloc_count - used; #if MI_SAMPLE==1 // for ==2 it is already counted in every `alloc/alloc.c:mi_page_alloc_zero` - if (theap!=NULL) { mi_theap_adjust_sample_countdown(theap,page,alloc_count); } + if (theapx!=NULL) { mi_theap_adjust_sample_countdown(theapx,page,alloc_count); } #endif // update stats? @@ -269,7 +269,7 @@ mi_assert_internal(mi_page_alloc_count(page) + mi_page_last_used(page) >= mi_page_used(page)); mi_assert_internal(mi_page_alloc_count(page) >= mi_page_last_alloc(page)); - mi_theap_page_merge_stats(theap, page, alloc_count, free_count); + mi_theap_page_merge_stats(theapx, page, alloc_count, free_count); } // Update stats for a page (and sample countdown) @@ -286,6 +286,9 @@ // Update the sampling countdown based on the current allocation count of the page void _mi_page_update_sample_countdown(mi_page_t* page) { + mi_assert_internal(mi_page_is_owned(page)); + // note: the threadid may not match and even be abandoned if we free multi-threaded (so we can not always use page->theap) + // adjust count down const size_t alloc_count = mi_page_alloc_count(page); if (alloc_count==0) { @@ -296,9 +299,8 @@ } #if MI_SAMPLE==1 // if ==2 the countdown is already always counted in `alloc/alloc.c:mi_page_alloc_zero_ex` else { - mi_theap_t* theap = mi_theap_of_page(page); - // mi_assert_internal(theap != NULL); - if (theap==NULL) return; + mi_theap_t* theap = mi_theap_of_page(page); // careful as the theap might not be valid + if (theap==NULL) return; // can be NULL on heap_destroy or metadata allocation etc. (and it is safe to ignore the sampling for now) mi_theap_adjust_sample_countdown(theap,page,alloc_count); // update last_alloc to the current alloc_count mi_assert_internal(alloc_count <= UINT16_MAX);