Skip to content

Commit dd713ed

Browse files
Brooooooklynclaude
andcommitted
fix(sys): vendor Apple THREAD_LOCAL patch in napi-rs/mimalloc fork
Apple targets in mimalloc v3 default to MI_TLS_MODEL_FIXED_SLOT, which stores the per-thread heap pointer in TCB[108]/[109] — a hardcoded slot shared by every image in the process. Two napi addons statically linking mimalloc into the same Node.js process collide on that slot, crashing the second one on load. The earlier -DMI_HAS_TLS_SLOT=0 workaround (routing Apple to MI_TLS_MODEL_DYNAMIC_PTHREADS) leaks a pthread key on process exit, which causes background threads (e.g. rayon workers from oxc) to abort when they next allocate. Switch to THREAD_LOCAL + RECURSE_GUARD by carrying the patch directly in our mimalloc fork (napi-rs/mimalloc, branch dev3) instead of rewriting prim.h at build time. Per-image __thread storage gives addons their own heap pointer; no pthread key means nothing for the destructor to break. - Repoint mimalloc3 submodule URL → https://github.com/napi-rs/mimalloc branch dev3 (currently v3.3.2 + the prim.h patch on top). - Drop the build.rs -DMI_HAS_TLS_SLOT=0 workaround. Supersedes #67. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent ec2fc80 commit dd713ed

3 files changed

Lines changed: 7 additions & 30 deletions

File tree

.gitmodules

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@
33
url = https://github.com/microsoft/mimalloc.git
44
[submodule "libmimalloc-sys/c_src/mimalloc3"]
55
path = libmimalloc-sys/c_src/mimalloc3
6-
url = https://github.com/microsoft/mimalloc.git
6+
url = https://github.com/napi-rs/mimalloc.git
7+
branch = dev3

libmimalloc-sys/build.rs

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -76,34 +76,10 @@ fn main() {
7676
cmake_config.define("MI_LOCAL_DYNAMIC_TLS", "ON");
7777
}
7878

79-
// On Apple targets, mimalloc v3's `prim.h` selects
80-
// `MI_TLS_MODEL_FIXED_SLOT` and hardcodes the per-thread `theap`
81-
// pointer at TCB[108]/[109], reading/writing the slot directly
82-
// through `tpidrro_el0` (arm64) or `%gs:` (x86_64) rather than
83-
// through `pthread_setspecific`. The slot numbers are not allocated
84-
// via `pthread_key_create`; the same header notes the caveat:
85-
// "This goes wrong though if the OS or a library uses the same
86-
// fixed slot."
87-
//
88-
// When a process loads more than one image that statically links
89-
// mimalloc-safe (e.g. two napi addons in one Node.js process),
90-
// each image has its own mimalloc state but every image's
91-
// `_mi_theap_default()` reads and writes the same TCB[108] on any
92-
// given thread — the instances overwrite each other's pointers.
93-
//
94-
// `-DMI_HAS_TLS_SLOT=0` makes the cascade in `prim.h` skip the
95-
// FIXED_SLOT branch on Apple and fall through to
96-
// `MI_TLS_MODEL_DYNAMIC_PTHREADS`, whose accessors use
97-
// `pthread_{get,set}specific` with a key allocated per image via
98-
// `pthread_key_create`. Different images then use distinct keys and
99-
// no longer share TLS storage. `prim.h` notes this path is "a bit
100-
// slower"; the impact has not been measured here.
101-
//
102-
// Gated on the `v3` feature: v2 has a separate Apple fast path
103-
// controlled by `MI_TLS_SLOT` and is not affected by this define.
104-
if target_os == "macos" && env::var_os("CARGO_FEATURE_V3").is_some() {
105-
cmake_config.cflag("-DMI_HAS_TLS_SLOT=0");
106-
}
79+
// Note: the previous `-DMI_HAS_TLS_SLOT=0` workaround for Apple has been
80+
// replaced by a vendored source patch in our mimalloc fork (napi-rs/mimalloc
81+
// dev3) that routes Apple to `MI_TLS_MODEL_THREAD_LOCAL + MI_TLS_RECURSE_GUARD`
82+
// directly in `include/mimalloc/prim.h`. See that patch for the full rationale.
10783

10884
if (target_os == "linux" || target_os == "android")
10985
&& env::var_os("CARGO_FEATURE_NO_THP").is_some()

libmimalloc-sys/c_src/mimalloc3

0 commit comments

Comments
 (0)