mirror of
https://github.com/jemalloc/jemalloc.git
synced 2026-04-14 14:41:42 +03:00
Fix missing release of acquired neighbor edata in extent_try_coalesce_impl
When emap_try_acquire_edata_neighbor returned a non-NULL neighbor but the size check failed, the neighbor was never released from extent_state_merging, making it permanently invisible to future allocation and coalescing operations. Release the neighbor when it doesn't meet the size requirement, matching the pattern used in extent_recycle_extract.
This commit is contained in:
parent
3f6e63e86a
commit
675ab079e7
2 changed files with 73 additions and 18 deletions
44
src/extent.c
44
src/extent.c
|
|
@ -916,15 +916,20 @@ extent_try_coalesce_impl(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
|
|||
size_t max_next_neighbor = max_size > edata_size_get(edata)
|
||||
? max_size - edata_size_get(edata)
|
||||
: 0;
|
||||
if (next != NULL && edata_size_get(next) <= max_next_neighbor) {
|
||||
if (!extent_coalesce(
|
||||
tsdn, pac, ehooks, ecache, edata, next, true)) {
|
||||
if (ecache->delay_coalesce) {
|
||||
/* Do minimal coalescing. */
|
||||
*coalesced = true;
|
||||
return edata;
|
||||
if (next != NULL) {
|
||||
if (edata_size_get(next) > max_next_neighbor) {
|
||||
emap_release_edata(
|
||||
tsdn, pac->emap, next, ecache->state);
|
||||
} else {
|
||||
if (!extent_coalesce(tsdn, pac, ehooks, ecache,
|
||||
edata, next, true)) {
|
||||
if (ecache->delay_coalesce) {
|
||||
/* Do minimal coalescing. */
|
||||
*coalesced = true;
|
||||
return edata;
|
||||
}
|
||||
again = true;
|
||||
}
|
||||
again = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -934,16 +939,21 @@ extent_try_coalesce_impl(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
|
|||
size_t max_prev_neighbor = max_size > edata_size_get(edata)
|
||||
? max_size - edata_size_get(edata)
|
||||
: 0;
|
||||
if (prev != NULL && edata_size_get(prev) <= max_prev_neighbor) {
|
||||
if (!extent_coalesce(tsdn, pac, ehooks, ecache, edata,
|
||||
prev, false)) {
|
||||
edata = prev;
|
||||
if (ecache->delay_coalesce) {
|
||||
/* Do minimal coalescing. */
|
||||
*coalesced = true;
|
||||
return edata;
|
||||
if (prev != NULL) {
|
||||
if (edata_size_get(prev) > max_prev_neighbor) {
|
||||
emap_release_edata(
|
||||
tsdn, pac->emap, prev, ecache->state);
|
||||
} else {
|
||||
if (!extent_coalesce(tsdn, pac, ehooks, ecache,
|
||||
edata, prev, false)) {
|
||||
edata = prev;
|
||||
if (ecache->delay_coalesce) {
|
||||
/* Do minimal coalescing. */
|
||||
*coalesced = true;
|
||||
return edata;
|
||||
}
|
||||
again = true;
|
||||
}
|
||||
again = true;
|
||||
}
|
||||
}
|
||||
} while (again);
|
||||
|
|
|
|||
|
|
@ -121,7 +121,52 @@ TEST_BEGIN(test_alloc_free_purge_thds) {
|
|||
}
|
||||
TEST_END
|
||||
|
||||
TEST_BEGIN(test_failed_coalesce_releases_neighbor) {
|
||||
test_skip_if(!maps_coalesce);
|
||||
|
||||
test_data_t *test_data = init_test_data(-1, -1);
|
||||
size_t old_lg_extent_max_active_fit = opt_lg_extent_max_active_fit;
|
||||
opt_lg_extent_max_active_fit = 0;
|
||||
|
||||
bool deferred_work_generated = false;
|
||||
size_t unit = SC_LARGE_MINCLASS;
|
||||
size_t alloc_size = 4 * unit;
|
||||
edata_t *edata = pa_alloc(TSDN_NULL, &test_data->shard, alloc_size,
|
||||
PAGE,
|
||||
/* slab */ false, sz_size2index(alloc_size), /* zero */ false,
|
||||
/* guarded */ false, &deferred_work_generated);
|
||||
expect_ptr_not_null(edata, "Unexpected pa_alloc() failure");
|
||||
|
||||
void *tail_addr = (void *)((uintptr_t)edata_base_get(edata) + unit);
|
||||
expect_false(pa_shrink(TSDN_NULL, &test_data->shard, edata, alloc_size,
|
||||
unit, sz_size2index(unit), &deferred_work_generated),
|
||||
"Unexpected pa_shrink() failure");
|
||||
|
||||
edata_t *tail = emap_edata_lookup(
|
||||
TSDN_NULL, &test_data->emap, tail_addr);
|
||||
expect_ptr_not_null(tail, "Expected dirty tail extent after shrink");
|
||||
expect_ptr_eq(
|
||||
edata_base_get(tail), tail_addr, "Unexpected tail extent address");
|
||||
expect_zu_eq(
|
||||
edata_size_get(tail), 3 * unit, "Unexpected tail extent size");
|
||||
expect_d_eq(edata_state_get(tail), extent_state_dirty,
|
||||
"Expected tail extent to start dirty");
|
||||
|
||||
pa_dalloc(
|
||||
TSDN_NULL, &test_data->shard, edata, &deferred_work_generated);
|
||||
|
||||
tail = emap_edata_lookup(TSDN_NULL, &test_data->emap, tail_addr);
|
||||
expect_ptr_not_null(
|
||||
tail, "Expected oversized dirty neighbor to remain discoverable");
|
||||
expect_d_eq(edata_state_get(tail), extent_state_dirty,
|
||||
"Failed coalesce must release oversized dirty neighbor");
|
||||
|
||||
opt_lg_extent_max_active_fit = old_lg_extent_max_active_fit;
|
||||
}
|
||||
TEST_END
|
||||
|
||||
int
|
||||
main(void) {
|
||||
return test(test_alloc_free_purge_thds);
|
||||
return test(
|
||||
test_alloc_free_purge_thds, test_failed_coalesce_releases_neighbor);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue