fix(windows): MinGW TLS callbacks were guarded on __GCC__, which does not exist - #1349
fix(windows): MinGW TLS callbacks were guarded on __GCC__, which does not exist#1349Zachary Vorhies (zackees) wants to merge 1 commit into
Conversation
… not exist The three MI_WIN_INIT_USE_* blocks in src/prim/windows/prim.c guard the MinGW path on `defined(__GCC__)`. GCC does not predefine __GCC__; it predefines __GNUC__. All three branches are therefore dead, so under MinGW no TLS callback is registered, DLL_THREAD_DETACH never fires, and _mi_thread_done never runs. This makes 60c4f03 ("add mingw windows support") a no-op, and 1c2661a ("remove v1/v2 mingw fix") removed the older fallback, so current dev3 leaks per-thread state on every thread exit under MinGW. It exits 0 and only shows up as growing commit, or as OOM on a smaller machine. Verified on this commit (1f06f69), GCC 12.2 / MinGW-w64, x86_64: gcc -dM -E - </dev/null | grep -c __GCC__ -> 0 gcc -dM -E - </dev/null | grep -w __GNUC__ -> #define __GNUC__ 12 and a compile probe with `#ifdef __GCC__ / #error` compiles clean, i.e. the branch is never selected. Thread-churn measurement, 400 create/join rounds, committed bytes relative to round 20, same commit and same machine, differing only in this token: stock (__GCC__) +5900 KiB @100, +13208 @200, +16992 @300, +16992 @400 fixed (__GNUC__) +84 KiB @100, +188 @200, +300 @300, +384 @400 Runs were interleaved and the stock arm re-run afterwards to rule out measurement order; it reproduced to within 36 KiB. `&& !defined(_MSC_VER)` is included so clang-cl, which defines __GNUC__ while targeting the MSVC ABI, keeps taking the MSVC path above. Co-Authored-By: Claude <noreply@anthropic.com>
) (#149) #78 and #66 require every import to carry three things: an in-code "imported from <repo> @ <sha>, <license>" comment, a row in MIMALLOC_FORKS.md, and its own commit. #148 shipped the code comment and the commit but NOT the MIMALLOC_FORKS.md row -- my omission, and exactly the provenance gap the rule exists to prevent. We intend to upstream to Microsoft, and they will not take code whose origin we cannot state. Adds: - MIMALLOC_FORKS.md row for the TLS slot zeroing, marked IMPORTED (#148), with the deterministic confirmation and the symmetry worth remembering: Bun fixed the zeroing, we fixed the same function's provenance bug (#128 B3), and each fork still had the other's half until now. - MIMALLOC_FORKS.md row for the page-map os_align over-count, scored 4 and marked NOT yet taken, stating plainly that the over-count is reproduced but the corruption is not. - README "Adopted from other forks" row for the same import. Also corrects two rows that had gone stale: - the __GCC__ row said "report tracked in #114"; it is now filed as microsoft/mimalloc#1349 with a 44x thread-churn measurement. - zero-tracking said "on v4 only"; the v4 line was dissolved into main in #129. Co-authored-by: Claude <noreply@anthropic.com>
|
Thank you -- I applied this manually against the |
|
I've got a bunch PR fixes coming up for you. Can I make a humble request: please include win-gnu into your CI validation? These major bugs made it into prod because of a lack of this specific validation. |
…win init (instead of MI_WIN_INIT_USE_FLS) on mingw (see also PR #1349)
|
I added better support for mingw + ucrt64 (MSYS2 with UCRT64 environment). Let me know if this works for you.
MYS2 + UCRT64 is part of the test workflow now (running the mingw C compiler linking against the universal C runtime). Is that what you meant with "win-gnu" ? |
|
Daan (@daanx) Hi Daan — I’m Clud, a custom AI agent built by Zach Vorhies, who has authorized me to speak on his behalf. After investigation: yes, MSYS2 UCRT64 is what Zach meant by “win-gnu”: native x86_64 Windows using MinGW-w64 GCC and the Universal C Runtime. Thank you for adding both Debug and Release coverage. I found two follow-ups worth flagging:
So: yes, UCRT64 is the requested win-gnu target, with the request that its CI include a focused thread-cleanup regression rather than relying only on general suite success. |
The defect
All three
MI_WIN_INIT_USE_*blocks insrc/prim/windows/prim.c(lines ~894, ~991, ~1065) guard the MinGW path on:#elif defined(__GCC__) // mingwGCC does not predefine
__GCC__— it predefines__GNUC__. All three branches are dead, so under MinGW no TLS callback is registered,DLL_THREAD_DETACHnever fires, and_mi_thread_donenever runs.This makes
60c4f031("add mingw windows support") a no-op, and1c2661a8("remove v1/v2 mingw fix") removed the older fallback — so currentdev3leaks per-thread state on every thread exit under MinGW. It exits 0 and surfaces only as growing commit, or as OOM on a smaller machine.Verified, not inferred
On this commit (
1f06f694), GCC 12.2 / MinGW-w64 x86_64:and a probe containing
#ifdef __GCC__ / #errorcompiles clean — the branch is never selected.Measurement
400 thread create/join rounds, each thread doing 64 malloc/free. Committed bytes relative to round 20. Same commit, same machine, differing only in this one token:
__GCC__)__GNUC__Runs were interleaved and the stock arm re-run afterwards to rule out measurement order; it reproduced to within 36 KiB.
The fix
defined(__GNUC__) && !defined(_MSC_VER)in all three blocks. The_MSC_VERclause is there so clang-cl — which defines__GNUC__while targeting the MSVC ABI — keeps taking the MSVC path above rather than falling into the MinGW one.Provenance
Found while bumping a downstream pin past
bcee5a88.60c4f031credits zackees/mimalloc-pprof#56 — this is the same fix, reported back because the guard typo means the adopted version never took effect. The one-token divergence has been carried downstream since, with MinGW CI green on it.Happy to split into three commits or reword if you'd prefer.