Summary
Starting with v3.4.0 (and still present in v3.4.1), programs that use mimalloc on macOS/arm64 and also link CoreFoundation can crash reliably at thread-exit time with a heap-corruption abort:
abort -> malloc_vreport -> malloc_report ->
___BUG_IN_CLIENT_OF_LIBMALLOC_POINTER_BEING_FREED_WAS_NOT_ALLOCATED ->
_pthread_tsd_cleanup -> _pthread_exit
git bisect (v3.3.2 good, v3.4.1 bad) lands on exactly one commit:
f211b37 — "update macOS TLS slots to 126/127 to avoid Swift slots"
which moved MI_TLS_MODEL_FIXED_SLOT_DEFAULT/MI_TLS_MODEL_FIXED_SLOT_CACHED from raw pthread TSD slots 108/109 to 126/127 in include/mimalloc/prim.h. The immediate parent commit, 41dd408, is clean (0 crashes across many runs with the same repro). v3.3.2 is also clean.
Environment
- macOS 26.5.1 (build 25F80), arm64 (Apple Silicon, MacBookAir10,1)
- Apple clang version 21.0.0 (clang-2100.1.1.101), also reproduced with Homebrew
llvm@22
- mimalloc built as a static library (
MI_BUILD_SHARED=OFF), default options otherwise
Minimal repro
Does not reproduce with a plain pthread-only program. Reproduces reliably (SIGTRAP, first iteration, every run) as soon as CoreFoundation is linked — even though the program never calls a single CF function; just having the framework loaded is enough. This suggests slot 126 or 127 collides with something CoreFoundation's own startup claims on this OS version, even though neither slot appears assigned in Apple's public darwin-libpthread's tsd_private.h as of this report (that header lists Swift at 100-109, libmalloc at 110-114, libdispatch workgroups at 115-119, and nothing between 120 and 189 except PerfUtils at 190-194 -- so either that public header lags the shipping OS's actual internal reservations, or the collision mechanism is different from a documented-slot collision).
#include <mimalloc.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#define NUM_THREADS 8
#define NUM_ITERATIONS 50
#define ALLOCS_PER_THREAD 1000
static void* worker(void* arg) {
(void)arg;
for (int i = 0; i < ALLOCS_PER_THREAD; i++) {
size_t sz = 32 + (size_t)(i % 512);
void* p = mi_malloc(sz);
if (p) memset(p, 0xAB, sz);
void* q = mi_malloc(16);
mi_free(p);
mi_free(q);
}
return NULL;
}
int main(void) {
for (int iter = 0; iter < NUM_ITERATIONS; iter++) {
pthread_t threads[NUM_THREADS];
for (int t = 0; t < NUM_THREADS; t++) pthread_create(&threads[t], NULL, worker, NULL);
for (int t = 0; t < NUM_THREADS; t++) pthread_join(threads[t], NULL);
printf("iteration %d done\n", iter);
}
printf("ALL ITERATIONS COMPLETE, NO CRASH\n");
return 0;
}
Build (the -framework CoreFoundation is the load-bearing part):
cc -O2 -I <mimalloc>/include repro.c <mimalloc-build>/libmimalloc.a -o repro -lpthread -framework CoreFoundation
./repro
How we found this
We use mimalloc in a Node.js native addon. Bumping our pin from v3.3.2 to v3.4.1 (to pick up one of the issue #1271 fixes) caused a Node.js worker-thread test to start crashing 100% of the time on macOS CI, with the same crash signature as above (multiple pthread-created threads aborting identically at exit). We bisected within mimalloc's own history against a real reproduction of that crash before distilling it down to the standalone repro above.
Workaround
We've reverted to v3.3.2 for now. Commit 41dd408 (the parent of f211b37) also works and has ~88 more commits of fixes over v3.3.2, including several issue #1271 items, so it may be a better interim base for anyone who needs those fixes without the new crash.
Happy to provide the full macOS .ips crash report (with paths/pids redacted) if useful.
Summary
Starting with v3.4.0 (and still present in v3.4.1), programs that use mimalloc on macOS/arm64 and also link
CoreFoundationcan crash reliably at thread-exit time with a heap-corruption abort:git bisect(v3.3.2 good, v3.4.1 bad) lands on exactly one commit:f211b37 — "update macOS TLS slots to 126/127 to avoid Swift slots"
which moved
MI_TLS_MODEL_FIXED_SLOT_DEFAULT/MI_TLS_MODEL_FIXED_SLOT_CACHEDfrom raw pthread TSD slots 108/109 to 126/127 ininclude/mimalloc/prim.h. The immediate parent commit, 41dd408, is clean (0 crashes across many runs with the same repro). v3.3.2 is also clean.Environment
llvm@22MI_BUILD_SHARED=OFF), default options otherwiseMinimal repro
Does not reproduce with a plain
pthread-only program. Reproduces reliably (SIGTRAP, first iteration, every run) as soon asCoreFoundationis linked — even though the program never calls a single CF function; just having the framework loaded is enough. This suggests slot 126 or 127 collides with something CoreFoundation's own startup claims on this OS version, even though neither slot appears assigned in Apple's publicdarwin-libpthread'stsd_private.has of this report (that header lists Swift at 100-109, libmalloc at 110-114, libdispatch workgroups at 115-119, and nothing between 120 and 189 except PerfUtils at 190-194 -- so either that public header lags the shipping OS's actual internal reservations, or the collision mechanism is different from a documented-slot collision).Build (the
-framework CoreFoundationis the load-bearing part):How we found this
We use mimalloc in a Node.js native addon. Bumping our pin from v3.3.2 to v3.4.1 (to pick up one of the issue #1271 fixes) caused a Node.js worker-thread test to start crashing 100% of the time on macOS CI, with the same crash signature as above (multiple
pthread-created threads aborting identically at exit). We bisected within mimalloc's own history against a real reproduction of that crash before distilling it down to the standalone repro above.Workaround
We've reverted to v3.3.2 for now. Commit 41dd408 (the parent of f211b37) also works and has ~88 more commits of fixes over v3.3.2, including several issue #1271 items, so it may be a better interim base for anyone who needs those fixes without the new crash.
Happy to provide the full macOS
.ipscrash report (with paths/pids redacted) if useful.