ReviewOS

zig-utils/zig-js

JSON.stringify: securely seed active-cycle identity placement

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

Parents: #493, #473 Follow-up to: #556 Related: #857

Problem

#556 correctly replaced quadratic active-ancestor scans with a relocation-stable identity index after depth 32, but that promoted index is still std.AutoHashMapUnmanaged(JsonObjectIdentity, void). Managed GC identities are monotonically issued and graph depth/allocation order are JavaScript-controlled, so hostile input can precompute a process-default collision family and recover superlinear probe work on the exact deep path the index is intended to bound. Arena/static addresses are separately tagged but likewise should not be treated as a collision defense.

Scope

  • Give the promoted invocation-local active-cycle index one unpredictable exact-identity hash context sourced from the existing interpreter secure-seed stream.
  • Keep the first 32 active ancestors allocation- and entropy-free.
  • Publish the context only after successful promotion; failed promotion leaves the ordered path authoritative, the index/context unpublished, and retry coherent.
  • Preserve relocation-stable managed identities, separately tagged address identities, exact LIFO membership, legal sibling aliases, direct/Proxy/replacer/toJSON cycles, callback order, and all #556 output/error behavior.
  • Retain bounded invocation-local storage and the existing scratch/output ownership.

Acceptance

  • The promoted cycle index has no default hash context.
  • A deterministic default-context collision family disperses under an installed seed while exact storage-tag/value equality remains authoritative.
  • Shallow paths request no seed; failed first promotion publishes no context/capacity/member and retry succeeds.
  • Deep acyclic paths, direct and callback-created cycles, repeated siblings, forced tree-walker/VM, precise/moving GC, and allocation replay remain exact.
  • Focused Debug/TSan, full units, exact-parent JSON.stringify Test262, threadfuzz, and ABI gates pass.

No-workaround rules

No lower depth cap, linear fallback after promotion, global visited set, predictable seed, address-secrecy assumption, source recognition, skipped callback, altered cycle error, third-party map, or weakened OOM/GC behavior.

9 days ago

Implemented and pushed to main in fix(json): seed active-cycle identity index (#858).

The promoted JSON.stringify ancestor index now uses one lazy secure exact-identity context. The first 32 ancestors remain allocation- and entropy-free; managed stable IDs and separately tagged addresses remain the equality authority; a failed first promotion leaves context, capacity, and membership unpublished and retries cleanly.

Evidence:

  • focused JSON Debug + TSan: 20/20, 0 failures/leaks;
  • full units: 2271 passed, 1 skipped, 0 failed, 0 leaked;
  • exact-parent Test262 JSON.stringify: 66/66 on both sides, byte-identical diagnostics, 0 flips;
  • threadfuzz: 400/400;
  • public C API: 117/117; Home private ABI: 447/447 plus 392/392 runtime shims.
9 days ago

Follow-up #859 landed in fix(structured-clone): secure object memoization (#859). The relocation-stable tagged object identity and keyed hash context introduced for JSON are now centralized in value.zig and reused by structured clone, removing the duplicate contract while retaining the #858 JSON atomicity/collision witnesses.

Sign in to comment on this issue.