issue51_musl_test.go
0 → 100644
+115
−0
+19
−35
Loading
___lock/___unlock emulated a C mutex using an atomic lock-word fast path plus a throwaway hand-off object stored in a map. When an unlocker took locksMu before a contending locker had registered its hand-off, ___unlock synthesized one and immediately discarded it; the waiter then blocked on a fresh, never-unlocked mutex forever, and the lock word was left non-zero, so every subsequent ___lock on that address also blocked. The process wedged permanently at zero CPU. The window is reachable through the exported API alone: localtime, localtime_r and mktime all take the single process-global timezone lock (_lock4) via __secs_to_zone on every call, so goroutines calling them concurrently can hit it. Reported against modernc.org/quickjs evaluating JS Date local-time getters. Replace the scheme with a per-address sync.Mutex, created lazily and reference-counted for cleanup. The opaque C lock word is no longer touched (nothing reads it outside these two functions); routing all mutual exclusion through the per-address mutex makes the hand-off race-free, so a release delivered before the waiter blocks is no longer lost. Add TestIssue51: a mutual-exclusion stress on ___lock/___unlock plus a concurrent localtime_r stress; both clean under -race. Fixes: #51 Co-Authored-By:Claude Opus 4.8 (1M context) <noreply@anthropic.com>