_mi_subproc(): fall back to the main subproc when tld->subproc is not yet set - #1391
_mi_subproc(): fall back to the main subproc when tld->subproc is not yet set#1391Antony Hosking (hosking) wants to merge 1 commit into
Conversation
…et set _mi_subproc() defends against partially-initialized thread state (issue microsoft#1289) by checking theap and theap->tld, but not the third member of the same initialization progression: a window where the theap and its tld exist while tld->subproc has not been set yet. In that window it returns NULL instead of falling back to _mi_subproc_main(), and the first caller that dereferences the result for stat accounting crashes (observed: a malloc-override shared library whose constructor allocates before process init completes faults at offsetof(mi_subproc_t, stats.commit_calls) in mi_subproc_stat_counter_increase(NULL, commit_calls, 1)). Extend the guard with the missing disjunct so the existing fallback covers the whole window it already defends; behavior for initialized threads is unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Thanks! I'll merge the commit .. but I don't quite understand how it can happen that the the |
|
Thanks! Reproduced, and I can answer the mechanism question precisely — it isn't a terminated thread, and it isn't a race: the NULL is a static initializer. The chain, all in current
|
Why though? The intention that mimalloc is initialized automatically is there - see So why did that not get executed (first)? |
_mi_subproc()(src/subproc.c) defends against partially-initialized thread state per issue #1289:There is a third member of the same initialization progression it does not cover: a window where the theap and its
tldexist buttld->subprochas not been set yet. In that window the function returns NULL instead of falling back to_mi_subproc_main(), and any caller that immediately dereferences the result for stat accounting faults.How we hit it (context, not required for the fix): a malloc-override shared library whose constructor allocates before mimalloc's process/thread init has completed. The first OS commit then runs
mi_subproc_stat_counter_increase(NULL, commit_calls, 1)and faults at address0x700, which is exactlyoffsetof(mi_subproc_t, stats.commit_calls)in our build — confirmed against the faulting address register. Any embedder whose constructor ordering puts allocation ahead of subproc wiring can reach the same window; it is not specific to our fork's extensions.Fix — extend the existing guard with the missing disjunct, so the fallback covers the whole progression it already defends:
This is what we run; it removed the constructor-time crash with no other change. The fallback (
_mi_subproc_main()) is the same one the existing guard already selects for the earlier stages of the same window, so behavior for initialized threads is unchanged. Validated againstdev3HEAD: clean build,mimalloc-test-apiandmimalloc-test-stresspass.