ReviewOS

zig-utils/zig-js

Private ABI: harden the process lifecycle registry

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

Parents: #493, #495 Related: #412, #867, #869

Problem

The process-wide private_global_lifecycles table maps opaque JSGlobalObject* addresses to the exact private creator/VM ownership record. Its callers accept arbitrary host-provided context pointers and correctly look them up before any dereference, but the table still uses std.AutoHashMapUnmanaged with predictable default bucket placement. Unlike the neighboring serialized-owner and script- execution-context registries, it also retains its allocation and hash regime after the final lifecycle is consumed.

Required design

  • Use a lazy secure exact-identity hash context independent from every other process and VM registry.
  • Publish the first context and lifecycle entry only after successful entropy and backing allocation; failure leaves an empty, unseeded, retryable table.
  • Keep every lookup/removal under the existing process mutex and compare full pointer integers before returning a record or dereferencing its stored context.
  • Centralize exact removal for isolation rollback, isolation replacement, and destruct-on-exit; when the last record is removed, free/reset the table so a later lifecycle starts with fresh entropy.
  • Preserve the exact private VM/context ownership, thread-affinity, process-ID transfer, failure rollback, and single-consumer teardown contracts.

No-workaround rules

  • No predictable or address-derived fallback seed, hash-only equality, linear scan, registry cap, leaked tombstone/backing allocation, forged-pointer dereference, weakened mutex/thread checks, alternate lifecycle path, or ABI signature/layout change.

Acceptance

  • Default-seed collision families disperse under the lifecycle registry's independent context while lookup/removal remain exact.
  • Entropy and first backing-allocation failures leave the table empty, unseeded, leak-free, and retryable.
  • Exact final removal frees and resets the process table; later insertion installs a fresh context without accepting retired or forged addresses.
  • Create, test-isolation transfer/rollback, destruct-on-exit, wrong-thread, null/foreign/stale, and concurrent lifecycle semantics remain unchanged.
  • Focused tests pass in Debug, ReleaseSafe, and TSan; Home/Bun lifecycle fixtures, ABI audits, threadfuzz, full units, and docs gates pass.
9 days ago

Implemented and pushed to main in 17dea421 — fix(private-abi): harden lifecycle registry (#870).

What landed:

  • Replaced the predictable process lifecycle map with an independent, lazy, securely seeded exact-pointer identity map.
  • Kept first publication failure-atomic across entropy and backing-allocation failure.
  • Centralized exact removal for isolation rollback, isolation replacement, and destruct-on-exit.
  • Freed/reset the table after its final record so the next lifecycle obtains fresh entropy.
  • Added exact collision, forged/retired address, duplicate, OOM retry, reseed, isolation-transfer, and concurrent create/destruct coverage.
  • Updated the pinned lifecycle contract, digest, ABI documentation, and generated docs manifest.

Verification:

  • Focused lifecycle tests: Debug 3/3, ReleaseSafe 3/3, TSan 3/3; zero leaks.
  • External private-global lifecycle fixtures: Debug, ReleaseSafe, and TSan passed.
  • threadfuzz -Dfuzz-iters=400: 400 programs from seed 1, 0 failures.
  • Exact clean test-parallel: 2,292 passed, 1 skipped, 0 failed, 0 leaked across 2,293 tests; 626.7 s / 10 shards.
  • C API: 117/117.
  • Home public ABI: 50/50.
  • Home private ABI: 447/447; 0 pending/unclassified.
  • Bun private ABI: 437/437; 0 pending/unclassified.
  • Private JSType ABI: Home 97, Bun 98, shared 97, Bun-only 1.
  • Docs: 50 pages built; 328/328 links resolve.
  • test262 flips: 0 (private native ABI boundary only; corpus not run).
9 days ago

All acceptance criteria are satisfied by the linked main-branch commit and the evidence above. Closing as completed.

9 days ago

The same secure exact-identity pattern is now applied to public/private inspector session handles by #871 in 516a8d59, including independent token/hash entropy, failure-atomic publication, final-entry reset, and forged/stale handle tests.

Sign in to comment on this issue.