ReviewOS

zig-utils/zig-js

Wasm: bound exception externref deduplication

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

Parents: #493, #486 Related: #141, #487, #490

Problem

When a Wasm exception reference is published, publishExceptionReference deduplicates direct and nested externref roots through std.AutoHashMapUnmanaged(u64, void). Externrefs carry arbitrary JavaScript Value.bits, Wasm tags can declare many parameters, and Zig hashes those attacker-influenced bits with fixed Wyhash seed 0. A caller can therefore precompute collision-heavy payload families on the exception/error path.

The resulting WasmException.externrefs slice is internal tracing metadata. Its order is unobservable; only exact root identity and uniqueness matter.

Scope

  • Replace fixed-seed hashing with bounded worst-case O(n log n) sort-and-unique over exact Value.bits.
  • Gather direct externref/hostref roots and roots retained by nested exnref payloads into invocation-owned scratch, sort without another allocation, compact duplicates in place, and copy only the unique prefix into owner storage.
  • Preserve exact Value identity, nested exception reachability, payload order, wrapper/rethrow identity, moving-GC rewriting, concurrent publication, and allocation-failure rollback.
  • Keep final root ownership and teardown unchanged while reducing temporary hash-table overhead.

No-workaround rules

  • No tag/payload count reduction, rejected externref values, hash-only equality, deterministic/public/address/time-derived fallback seed, linear quadratic deduplication, skipped duplicate roots without exact proof, global mutable seed, leaked scratch, or changed observable exception payload order.
  • No unrelated Wasm decode/validation, JS exception-constructor, GC aggregate, or public/private ABI change.

Acceptance

  • Published native exception roots use no default-context map and have a documented worst-case complexity bound.
  • A precomputed default-Wyhash collision family deduplicates to the exact unique Value.bits set, including direct and nested roots.
  • Empty, duplicate-heavy, moving-GC, rethrow/wrapper identity, concurrent publication, and exhaustive OOM tests pass.
  • Focused Debug, ReleaseSafe, TSan/no-GIL, Wasm API/spec, and GC lifetime gates pass.
  • Exact-parent Wasm conformance inventories have nonzero accounting and zero regressions.
  • Full unit and threadfuzz gates pass.
9 days ago

Implemented and pushed to main in 44c72b15.

Evidence:

  • chosen fixed-seed collision, nested-root, empty-input, and exhaustive OOM tests: 2/2 Debug and ReleaseSafe
  • Wasm exec exception coverage: 8/8 Debug and TSan
  • Wasm API exception coverage: 3/3 Debug
  • externref precise-GC/no-GIL coverage: 2/2 Debug and TSan
  • full unit rerun: 2,264 pass, 1 platform skip, 0 fail, 0 leak across 2,265 tests
  • threadfuzz: 400 programs, 0 failures
  • exact-parent packed Wasm inventories are byte-identical: 73 files, 18,778 pass, 13 pre-existing failures, 479 skips, 0 crashes
  • live Wasm evaluator build passed
  • public C API: 117/117 complete; Home private ABI: 447 implemented, 0 pending; 392/392 runtime shims passed

One earlier full-suite attempt reported NondeterministicMemoryUsage in the unrelated reentrant assignment roots unwind test. That exact test then passed alone, and the complete suite rerun passed cleanly; it is not omitted from the record. The external exception-handling corpus checkout is not initialized, so no claim is made for that unavailable live profile.

Native exception root publication now has a documented worst-case O(n log n) bound, exact Value.bits equality, in-place duplicate compaction, and unchanged owner teardown.

Sign in to comment on this issue.