← board

Audit: shared-global state — reentrancy & thread-safety

Scope

The compiler emits some per-call/per-site state as program globals (one shared BSS slot) rather than stack locals / caller-provided buffers. Two failure modes:

This ticket is the index; each concrete item has (or gets) its own ticket.

Findings

Reentrancy (worse — single-threaded recursion)

Thread-safety (concurrent only)

Intentional (NOT bugs)

Method to find more

Grep choke points: CurProc := -1 (forced-global AllocVar/AllocArray sites), BSS_* fixed scratch slots, and any Kind := skGlobal override. Each new forced global is a candidate — classify reentrancy vs thread-only by whether a call can occur between the write and the read of the slot.

Acceptance

Notes

Sweep done (2026-06-30)

Ran the choke-point grep (CurProc := -1, Kind := skGlobal). Result: the ONLY mid-routine forced-global (a CurProc:=-1 override while inside a routine) is the frozen-string Result (parser.inc 12542/12546) — DEFERRED as low-priority (niche frozen mode, [[bug-frozen-string-result-global-not-reentrant]]). Every other hit is benign: the if CurProc<0 then Kind:=skGlobal in AllocVar/AllocArray/ AllocDynArray (genuine globals, not overrides), and scope resets at routine end (parser.inc 13371/14104, pyparser 876/1055). Variant-box temp = already a routine -local (v97, done). So the reentrancy class is closed: nothing new bites single-threaded in managed mode. Remaining items (I/O scratch, heap) are thread-safety-only and need the thread runtime anyway.

Part of the multithreading epic (2026-06-30)

Umbrella: [[meta-multithreading]]. Invariant: threading is opt-in/off-by-default; single-threaded self-build stays byte-identical; no libc (Linux syscalls only).