ReviewOS

zig-utils/zig-js

Modules: securely seed runtime graph indexes

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

Parents: #493, #474 Related: #496, #761, #770, #848

Problem

The parser's source-name tables are securely keyed, but the evaluated module graph rebuilds source/host-controlled strings into default-context native hash tables:

  • the persistent canonical-path module registry;
  • private-loader path-to-source storage;
  • each module's raw-specifier dependency index;
  • each module's exported-name index;
  • temporary active module caches used by evaluation/GC fixtures.

Host-resolved paths and source-controlled import/export spellings can therefore be chosen to produce collision-heavy placement after parsing has completed. These tables are also long-lived identity and linking boundaries, so hardening must preserve exact module cache, cycle, namespace, and live-binding behavior.

Scope

  • Give every runtime module string table one lazy root-Shape-derived unpredictable context with exact-byte equality.
  • Request no entropy/key derivation for empty tables and no derivation per successfully installed path, dependency edge, export, lookup, or iterator; a failed first insertion retains no hidden candidate state.
  • Publish a table context only after its first insertion succeeds; first-insert allocation failure leaves zero capacity, zero entries, and no installed context.
  • Apply the hardened type uniformly to persistent registries, loader-provided sources, active/local caches, per-module dependencies, and per-module exports.
  • Preserve canonical path resolution, embedded NUL synthetic-module cache keys, module identity/reload deletion, import attributes/source/defer, cycles, star/indirect export ambiguity, namespace key ordering, TLA, dynamic import, GC tracing, and teardown.
  • Retain the existing realm-lock ownership for persistent registry/source mutation and iteration; do not add synchronization to immutable post-link dependency/export maps.

No-workaround rules

  • No path/specifier/export count or length cap, source normalization beyond existing canonical resolution, blacklist, public/address/time-derived seed, deterministic fallback, hash-only equality, linear fallback presented as hardening, duplicate module graph/cache, skipped export validation, or weakened cycle/ambiguity semantics.
  • No per-edge/per-lookup OS entropy request, network/filesystem policy change, public API/ABI change, or hidden cache warmup.

Acceptance

  • Every runtime module path/specifier/export table uses its installed secure exact-byte context for lookup, insertion, removal, and membership.
  • Empty and failed-first-insert tables remain unseeded/empty; successful tables derive once and retain the context through clear/reuse.
  • Default-seed collision families disperse under fixed keyed contexts without changing exact equality, including embedded NUL keys.
  • Focused normal, ReleaseSafe, TSan/no-GIL, moving-GC, OOM, deletion/reload, cycle, dynamic import, TLA, source/defer, namespace, and ambiguity tests pass with zero leaks/races.
  • Exact-parent relevant Test262 module inventories have nonzero accounting and zero regressions.
  • Full unit and threadfuzz gates pass.
9 days ago

Implemented and pushed as fix(modules): seed runtime graph indexes (#849).

All runtime module path, source, dependency, export, and active-cache indexes now use lazy root-Shape-derived keyed hashing with exact-byte equality. First-insert allocation failure is atomic; clear/reuse retains the installed context; existing realm-lock and GC ownership are preserved.

Evidence:

  • focused module units: 46/46 under TSan/no-GIL and 46/46 under ReleaseSafe, 0 leaks/races
  • full units: 2,249 passed, 1 platform skip, 0 failed, 0 leaked
  • threadfuzz: 400/400, 0 failures
  • exact-parent Test262: module-code 599/599 and dynamic-import 941/941 in both parent and candidate, 0 flips
  • required-VM parity: 599 and 941 agreements respectively, 0 divergences

Sign in to comment on this issue.