You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
A failing library load can still crash at exit on musl #423
ExitWithBusyWorker's load case segfaulted (exit code 139) in 1 of its 800 child runs on the Alpine musl job of main.yml run 41273728648, on 76441d8. In that case main returns while 8 workers keep calling cpp.Lib.load on a library that doesn't exist. The env and young cases passed, and the four main.yml runs before it passed the load case on musl too, so the crash is rare.
#371 kept the runtime's statics alive through exit, which fixed this case on glibc, macOS and Windows. On musl something the failing load path uses is still torn down under the worker. It could be one of our statics or musl's own state behind dlopen and dlerror. Telling which needs the crash reproduced on Alpine with a core dump.
Fixed in ca09e31. libgcc_s's finalizer frees the table that the unwinder looks frames up in. musl runs that finalizer after the atexit handlers, while other threads are still running, so a worker that threw after that point (here, from the failing cpp.Lib.load) crashed in _Unwind_Find_FDE. glibc builds are spared because that table is empty there.
hx::Boot now registers an atexit handler. It stops every other thread that runs Haxe code at its next safe point, the way a collection does, and never releases them, so none can throw once the finalizers start. A thread in a loop that never allocates is waited on for at most 100 ms. On Windows the handler is only registered when the runtime is linked into the executable.
ExitWithBusyWorker covers the crash. On Alpine it used to crash about once in 1600 runs, and in the first few runs once exit was slowed by 2 ms to widen the window. With the fix there were no crashes in 3,200 normal runs or in 16,000 slowed ones. ThreadEndsAtExit now checks that threads released after the static destructors stay stopped.
Activity
Suppress TSan's report of the exit park clearing allocation limits
dimensionscape commentedon Nov 2, 2026
Fixed in ca09e31. libgcc_s's finalizer frees the table that the unwinder looks frames up in. musl runs that finalizer after the atexit handlers, while other threads are still running, so a worker that threw after that point (here, from the failing
cpp.Lib.load) crashed in_Unwind_Find_FDE. glibc builds are spared because that table is empty there.hx::Bootnow registers an atexit handler. It stops every other thread that runs Haxe code at its next safe point, the way a collection does, and never releases them, so none can throw once the finalizers start. A thread in a loop that never allocates is waited on for at most 100 ms. On Windows the handler is only registered when the runtime is linked into the executable.ExitWithBusyWorker covers the crash. On Alpine it used to crash about once in 1600 runs, and in the first few runs once exit was slowed by 2 ms to widen the window. With the fix there were no crashes in 3,200 normal runs or in 16,000 slowed ones. ThreadEndsAtExit now checks that threads released after the static destructors stay stopped.
Park the other Haxe threads when the process exits