From 172787de9c18352bb29545da2426d9d61b260fc3 Mon Sep 17 00:00:00 2001 From: Martin Vogel Date: Tue, 15 Sep 2026 18:08:36 +0200 Subject: [PATCH] fix(mem): no glibc malloc_trim; the static Linux release links again The v0.10.9 release run (34948714902) failed in both Linux portable builds: the static link found malloc, free, realloc, calloc, memalign, valloc, pvalloc and posix_memalign defined twice, once by mimalloc's override and once by libc.a(malloc.o). Nothing in the build flags had changed since v0.10.8; what changed was one call. cbm_mem_release_to_os called glibc's malloc_trim(0), and that symbol lives only in malloc.o, so the reference pulled the whole object into the link next to mimalloc's definitions. Dynamic builds never noticed: interposition resolves the duplicates at load time, which is why the whole test matrix was green. The call was pointless where it broke things: on Linux and Windows the override routes every malloc to mimalloc, so glibc's heap holds nothing to trim and mi_collect(true) is the release. The branch and its include are gone; macOS keeps its pressure-relief call, since the system heap still serves everything outside the core there. Verification: the static build (scripts/build.sh CC=gcc CXX=g++ STATIC=1) in the local arm64 container reproduced the CI failure exactly before the change and links after it, the binary reporting its version; mem and parallel suites green on the host. Signed-off-by: Martin Vogel --- src/foundation/mem.c | 11 ++++++----- src/foundation/mem.h | 8 +++++--- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/foundation/mem.c b/src/foundation/mem.c index 753e101f9..48f0eeeff 100644 --- a/src/foundation/mem.c +++ b/src/foundation/mem.c @@ -35,9 +35,6 @@ #include /* malloc_zone_pressure_relief */ #else #include -#if defined(__GLIBC__) -#include /* malloc_trim */ -#endif #endif /* Does THIS build ask mimalloc to replace ordinary malloc process-wide? @@ -606,11 +603,15 @@ size_t cbm_mem_footprint(void) { } void cbm_mem_release_to_os(void) { + /* mi_collect is the release: on Linux and Windows mimalloc owns malloc, so + * there is no libc heap to trim. glibc's malloc_trim was called here once + * and cost the static Linux release its link: the reference pulls + * libc.a(malloc.o) in beside mimalloc's malloc/free (multiple definition, + * release run 34948714902, 2026-09-15). macOS keeps the system heap for + * everything outside the core, hence the pressure-relief call there. */ mi_collect(true); #if defined(__APPLE__) (void)malloc_zone_pressure_relief(NULL, 0); -#elif defined(__GLIBC__) - (void)malloc_trim(0); #endif } diff --git a/src/foundation/mem.h b/src/foundation/mem.h index 9b318fc9e..8fe909f0e 100644 --- a/src/foundation/mem.h +++ b/src/foundation/mem.h @@ -119,9 +119,11 @@ void cbm_mem_collect(void); size_t cbm_mem_footprint(void); /* Hand freed memory back to the OS on every allocator this process uses: - * mimalloc (mi_collect), the macOS system zones (malloc_zone_pressure_relief) - * and glibc (malloc_trim). Costs a few ms; call at phase boundaries after a - * bulk release, never per allocation. */ + * mimalloc (mi_collect) and, on macOS, the system zones + * (malloc_zone_pressure_relief). Never glibc's malloc_trim: on Linux mimalloc + * owns malloc, and the reference alone breaks the static release link. Costs + * a few ms; call at phase boundaries after a bulk release, never per + * allocation. */ void cbm_mem_release_to_os(void); /* ── Memory map: where does the process's memory actually live? ──────