ReviewOS

zig-utils/zig-js

GC: root tree-walker lexical scope restores across moving evaluation

#834
Closed chris opened this 9 days ago ·
9 days ago

Problem

Several tree-walker scope transitions save Interpreter.env as a raw pointer, execute arbitrary JavaScript, and restore the raw pointer afterward. A moving collection inside the nested evaluation can relocate the saved environment and make the deferred restore stale.

The audit found candidates in:

  • bare Annex B function-declaration block scopes;
  • with statement environments;
  • debugger evaluation state;
  • per-iteration for-in / for-of lexical environments;
  • switch CaseBlock environments.

This is the same root-discipline class exposed for try/catch/finally in #832, but it is intentionally separate from the synchronous defining-realm wrapper work in #830.

Required fix

  • Audit every tree-walker environment save/restore around callback-capable or allocating evaluation.
  • Root and reload saved environments across moving collection on normal and abrupt completion.
  • Add exact forced-moving witnesses for each distinct scope shape in tree-walker and required-bytecode modes.
  • Mirror any affected VM state handling where the bytecode path owns an equivalent raw environment.
  • Run focused TSan, full unit, and relevant test262 statement/eval coverage.
9 days ago

Landed 0e77d720 — fix(gc): root lexical scope restores across movement (#834) directly on main as Chris, without trailers. Annex B bare declarations, with statements, debugger evaluation, for-in/of and classic lexical loops, and switch CaseBlocks now restore environments through precise relocated roots. Reusable and disposal-owning per-iteration environments reload from their registered root slots instead of retaining old payload addresses.

Evidence: 22 forced-moving executions across tree-walker and required-bytecode modes; unsuppressed TSan pass in 205.4s; six environment/allocation-failure checks; relocation inventory 9 cell kinds / 27 pointer surfaces; pinned statement census 1182/1182 across with, for-in, for-of, switch, debugger, and Annex B; full units 2215 pass / 1 platform skip / 0 fail / 0 leak.

The audit also found a separate parser rejection for direct using declarations in switch CaseBlocks. It is tracked without a source-rewrite workaround in #835.

Sign in to comment on this issue.