From 7029edec971074d7ee3ca854b35cfa0ccb80b4f7 Mon Sep 17 00:00:00 2001 From: Ihar Hrachyshka Date: Thu, 9 Jul 2026 23:34:18 -0400 Subject: [PATCH] test: handle profiled xallocx no-grow in extent test With profiling active, xallocx may decline to grow an allocation that is not page-aligned. The profiling path can require sampled xallocx growth to use page-aligned pointers; otherwise it can return the old usable size without committing the purged tail. Observed on Darwin, where decommit/commit are real VM state changes. The shrink/purge half succeeds and records a decommit, then the profiling-limited grow skips the matching commit. This is not Darwin-specific. Linux no-overcommit should expose the same mismatch. Usual Linux overcommit behavior papers it over by making commit/decommit hooks report unsupported, so both sides of the old equality check stay false. Relax the default-path assertion only while profiling is active, and add a page-aligned case that still requires xallocx shrink and grow to succeed, preserving commit/merge coverage. Assisted-by: Codex gpt-5.5 xhigh --- test/integration/extent.c | 93 +++++++++++++++++++++++++++------------ 1 file changed, 66 insertions(+), 27 deletions(-) diff --git a/test/integration/extent.c b/test/integration/extent.c index 36091ac6..d0a4abb6 100644 --- a/test/integration/extent.c +++ b/test/integration/extent.c @@ -4,6 +4,57 @@ #include "jemalloc/internal/arena.h" +static void +test_decommit_commit(unsigned arena_ind, int flags, size_t large0, + size_t *purge_mib, size_t purge_miblen, bool expect_xallocx_success) { + void *p; + bool xallocx_success_b, xallocx_success_c; + + try_dalloc = false; + try_decommit = true; + p = mallocx(large0 * 2, flags); + expect_ptr_not_null(p, "Unexpected mallocx() error"); + did_decommit = false; + did_commit = false; + called_split = false; + did_split = false; + did_merge = false; + xallocx_success_b = (xallocx(p, large0, 0, flags) == large0); + expect_d_eq(mallctlbymib(purge_mib, purge_miblen, NULL, NULL, NULL, 0), + 0, "Unexpected arena.%u.purge error", arena_ind); + if (xallocx_success_b) { + expect_true(did_split, "Expected split"); + } + xallocx_success_c = (xallocx(p, large0 * 2, 0, flags) == large0 * 2); + if (expect_xallocx_success) { + expect_true(xallocx_success_b, "Expected xallocx shrink"); + expect_true(xallocx_success_c, "Expected xallocx grow"); + } + if (did_split && xallocx_success_c) { + expect_b_eq( + did_decommit, did_commit, "Expected decommit/commit match"); + } + if (xallocx_success_b && xallocx_success_c) { + expect_true(did_merge, "Expected merge"); + } + dallocx(p, flags); + try_dalloc = true; + try_decommit = false; +} + +static bool +prof_active_enabled(void) { + bool active = false; + size_t sz = sizeof(active); + + if (!config_prof) { + return false; + } + expect_d_eq(mallctl("prof.active", &active, &sz, NULL, 0), 0, + "Unexpected prof.active failure"); + return active; +} + static void test_extent_body(unsigned arena_ind) { void *p; @@ -11,9 +62,13 @@ test_extent_body(unsigned arena_ind) { size_t purge_mib[3]; size_t purge_miblen; int flags; - bool xallocx_success_a, xallocx_success_b, xallocx_success_c; + bool xallocx_success_a; + bool expect_xallocx_success; + bool prof_active; flags = MALLOCX_ARENA(arena_ind) | MALLOCX_TCACHE_NONE; + expect_xallocx_success = maps_coalesce && try_split && try_merge; + prof_active = prof_active_enabled(); /* Get large size classes. */ sz = sizeof(size_t); @@ -58,32 +113,16 @@ test_extent_body(unsigned arena_ind) { try_dalloc = true; /* Test decommit/commit and observe split/merge. */ - try_dalloc = false; - try_decommit = true; - p = mallocx(large0 * 2, flags); - expect_ptr_not_null(p, "Unexpected mallocx() error"); - did_decommit = false; - did_commit = false; - called_split = false; - did_split = false; - did_merge = false; - xallocx_success_b = (xallocx(p, large0, 0, flags) == large0); - expect_d_eq(mallctlbymib(purge_mib, purge_miblen, NULL, NULL, NULL, 0), - 0, "Unexpected arena.%u.purge error", arena_ind); - if (xallocx_success_b) { - expect_true(did_split, "Expected split"); - } - xallocx_success_c = (xallocx(p, large0 * 2, 0, flags) == large0 * 2); - if (did_split) { - expect_b_eq( - did_decommit, did_commit, "Expected decommit/commit match"); - } - if (xallocx_success_b && xallocx_success_c) { - expect_true(did_merge, "Expected merge"); - } - dallocx(p, flags); - try_dalloc = true; - try_decommit = false; + test_decommit_commit(arena_ind, flags, large0, purge_mib, purge_miblen, + expect_xallocx_success && !prof_active); + + /* + * Active profiling may decline to grow a non-sampled allocation if it + * is not page-aligned. Force page alignment to keep deterministic + * coverage for the successful grow/commit/merge path. + */ + test_decommit_commit(arena_ind, flags | MALLOCX_ALIGN(PAGE), large0, + purge_mib, purge_miblen, expect_xallocx_success); /* Make sure non-large allocation succeeds. */ p = mallocx(42, flags);