ReviewOS

zig-utils/zig-js

Wasm: seed exception graph collection identity

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

Parents: #493, #486 Related: #854, #490

Problem

collectGcAggregatesQuiescent traverses nested exnref payloads with std.AutoHashMapUnmanaged(*WasmException, void). JavaScript can construct wide and cyclic WebAssembly exception graphs, retain them through globals/tables/ wrappers, and trigger host collection. Zig's default pointer context has predictable placement, so allocation history and graph shape can amplify this quiescent collector before sweep.

#854 bounded exception externref root deduplication only and explicitly left Wasm GC aggregate collection out of scope.

Required design

  • Replace the default pointer set with a lazy exact exception-identity index seeded from secure host entropy, with no deterministic/address/time fallback.
  • Publish the context only after the first backing allocation succeeds. Entropy or allocation failure must leave an empty, retryable index.
  • Keep exception traversal iterative, exact, cycle-safe, and allocation-failure atomic. Any mark-phase failure must perform no aggregate sweep.
  • Preserve nested payload reachability, wrapper roots, globals/tables/active and external roots, cross-instance ownership, mark epochs, and reclamation.
  • Do not add a mutable non-atomic exception mark epoch: exception references may cross instance graphs, so independent collections must not race on shared exception state.

No-workaround rules

  • No exception/tag/payload caps, rejected graphs, skipped edges, hash-only equality, predictable fallback seed, quadratic scan, recursive traversal, leaked scratch state, partial sweep, global mutable seed, or weakened tests.

Acceptance

  • A deterministic legacy pointer collision family disperses under the keyed context with exact lookup/removal.
  • Entropy failure and first-allocation failure publish no context/table and exact retry succeeds.
  • Wide/deep/cyclic nested exception graphs terminate and retain every reachable aggregate; unreachable aggregates reclaim exactly.
  • Exhaustive OOM tests prove mark failure performs no sweep and retry preserves the existing reclamation result.
  • Focused collection/exception tests pass in Debug, ReleaseSafe, and TSan.
  • Wasm API/spec and GC lifetime gates, threadfuzz, full units, public C API, and pinned private ABI audits/runtime pass with exact linked evidence.
9 days ago

Implemented and pushed to main in fix(wasm): seed exception collection identity (#864).

The collector now uses an invocation-local, exact pointer identity set whose bucket placement is seeded from secure host entropy. The seed is published only after the first backing allocation succeeds; entropy or allocation failure leaves an empty, retryable set. Traversal remains iterative and cycle-safe, and every mark-phase failure exits before sweep. No mutable exception epoch was added, so exceptions shared across instance graphs do not acquire a new collection race.

Validation:

  • adversarial legacy-collision, 4,096-node cyclic graph, and exhaustive allocation-failure tests: 3/3 in Debug, ReleaseSafe, and TSan;
  • broader wasm.exec GC group: 12/12 in Debug, ReleaseSafe, and TSan;
  • exception coverage: 59/59 in ReleaseSafe and TSan, with no leaks or races;
  • Wasm API coverage: 45/45 in Debug; precise Wasm GC wrapper-lifetime test 1/1 in TSan;
  • wasm-spec-eval builds; packed Wasm inventory is byte-identical to exact parent c53d76a4: 73 files, 18,778 pass, 13 existing failures, 479 skip, 0 crash (the 13 failures are the unchanged baseline, not reported as a passing gate);
  • deterministic default threadfuzz: 400 programs from seed 1, 0 failures;
  • exact pushed commit in a clean checkout: 2,283 passed, 1 skipped, 0 failed, 0 leaked across 10 unit shards;
  • public C audit: 117/117 declarations and symbols; Home public: 50/50; Home private: 447/447; Bun private: 437/437; private JSType audit clean; Home private runtime shims: 392/392.

This completes every acceptance item without graph caps, fallback seeds, partial traversal, quadratic scans, recursion, or partial sweep.

Sign in to comment on this issue.