ABI: Batch ABI 43 platform work and shared-memory vfork - #1240
Open
brandonpayton wants to merge 83 commits into
Open
ABI: Batch ABI 43 platform work and shared-memory vfork#1240brandonpayton wants to merge 83 commits into
brandonpayton wants to merge 83 commits into
Conversation
Serialize supported tagged catch state per activation and reject non-reconstructible reference and table state. Require the ABI 43 safety capability across build and host launch boundaries.
Give Node and browser process Workers the same versioned reference graph, external-reference authority, imported state, table replicas, exceptions, and replay-gate owners. Recreate main and side-module Store-local identities before continuation rewind. Release temporary roots on completion, abort, exec, and teardown. Stage dynamic loading as host-only prepare/next operations followed by ordinary Wasm initializers. Serialize pthread loader ownership, replay exact module layouts, and defer signal delivery until libc regains the guest boundary.
Require ABI 43 activation-state-safe capability, exact role metadata, zero native start sections, and staged-loader inventory across package receipts, indexes, sidecars, Homebrew validation, and shell guards. Build valid compiler-EH fixtures normally instead of routing them to an unsupported bucket. Select the declared LLVM archiver on Darwin so final-key source rebuilds remain reproducible. Treat executable kernel.kernel_fork and side-module env.fork as fork-entry evidence in the common binary inventory. Keep the current Homebrew program projection and standalone resolver unchanged; regenerate both once from the coherent batch tip.
Move host-to-kernel structured transfers into bounded, ABI-described scratch regions owned by the kernel. Replace guest-pointer-dependent marshalling for process, IPC, socket, spawn, and signal state with checked wire formats and exact pointer-width layouts. Generate matching Rust, C, and TypeScript metadata, enforce allocation and copy-back bounds, and cover native, wasm32, wasm64, Node, and browser paths. This is the foundational ABI 43 change; later commits close additional ownership and publication seams.
Package cached toolchain sysroots without embedding the source worktree path. Reconstruct the expected layout after cache restore so the action works in a different checkout and on a different runner.
Declare and stage the wasm64 examples needed by browser tests instead of assuming that a previous local build left them in place. Teach CI scope detection, workspace packing, and browser fetch tests to enforce the fixture manifest.
Finish moving blocked retries, VFS operations, IPC, sockets, process state, and scalar results behind kernel-owned scratch and entry gates. Remove remaining host dependence on mutable guest pointer layouts. Apply the same ownership rules in Node and browser workers. Add focused tests for append and offset behavior, environment transactions, worker lifecycle, and fail-stop scratch violations, then refresh the ABI 43 snapshot and generated bindings.
Publish each kernel scratch region and its generated contract as one atomic ABI state. Fail closed when the host observes a missing, stale, or partially initialized region rather than continuing with mixed metadata. Refresh the ABI projection and exercise publication, reusable kernel stacks, and fail-stop validation in the shared Node and browser paths.
Honor the Node bridge endpoint-ownership flags after FIN or cleanup. A close may synchronously reclaim the global pipe slot, so later pumps must neither query nor notify its reusable numeric index.
Give Node conformance runs an explicit, session-owned VFS root and mount lifecycle. Prevent tests from depending on or mutating ambient host storage, and make teardown retire the same mount state that was admitted. Route the libc, POSIX, and Sortix runners through that production host path and cover mount creation, export, and cleanup.
Reject VFS seed entries whose normalized paths shadow an existing session mount or another seed. This keeps the admitted image authoritative and prevents path ordering from silently changing machine state.
Snapshot executable bytes when the resolver admits a program instead of rereading a mutable host file during worker launch. The process now runs the exact image that passed ABI and artifact validation. Cover package resolution and rootfs export while preserving the same behavior in the shared Node and browser launch machinery.
Apply retired-memory debt admission synchronously before ordinary fork creates or copies a child WebAssembly.Memory. Return EAGAIN when the bounded debt limit is saturated, without yielding across the parent snapshot or allocating another complete address space. Keep ordinary fork semantics independent from vfork and prove that the rejected path performs no child allocation or copy.
Add explicit ownership tokens for host workers that intentionally share one process-memory backing. Count the backing once, retire it only after the final alias crosses its quiescence fence, and propagate forced termination until final release. This ownership mechanism does not reinterpret ordinary fork: only callers with an explicit shared-memory transaction may retain an alias.
Drive ordinary-fork admission through the production kernel entry gate instead of constructing a partial worker object. Verify that a retired-memory EAGAIN removes the provisional child and completes the parent mailbox with the truthful error.
Allow a separately launched child worker to borrow the parent process continuation while keeping worker-local replay control state independent. Rebuild main-module and active side-module references from admitted bytes without handing the child authority over parent continuation storage. Gate completion through an explicit lifetime coordinator and cover main, dynamic-link, and active-side replay in Node, Chromium, Firefox, and WebKit fixtures.
Document the fork memory root cause, the shared-memory vfork design, ordinary-fork admission, rejected alternatives, ABI implications, and the evidence still required for release. Add a component resident-set-size harness that separates worker, module, shared-memory, full-clone, and sparse-clone costs. Its results are scoped to those components and do not claim Homebrew application performance.
Binaryen --fpcast-emu rewrites indirectly called functions to a uniform i64 trampoline signature. Host pthread entry calls were still passing a plain JavaScript number, which traps when the wrapper expects BigInt arguments. Build the call arguments from the WebAssembly function parameter count: preserve the plain pointer ABI for ordinary entries and use a BigInt pointer plus zero-filled i64 slots for fpcast trampolines. ABI 43 forward-port: fork-from-thread children now enter through the exported wpk_fork_resume_thread helper. Retain that plain replay ABI and apply fpcast-expanded arguments only where the host calls the table entry directly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> (cherry picked from commit a2b70da)
Character-special mode is broader than terminal identity. Kandelo encoded host terminal stdio and virtual devices such as /dev/null, framebuffer, audio, and DRM as CharDevice, so terminal probes could mistake any virtual character device for an interactive terminal. Derive terminal identity from the open file description. Dedicated PTY master and slave types are terminals; legacy host stdio is a terminal only when its stable canonical path and host handle agree. Reuse that result for isatty, termios, ioctl namespace gating, and fpathconf. The ABI 43 forward-port retains the current exact 60-byte termios layout. This changes no syscall number, marshalling rule, exported signature, structure layout, generated binding, or VFS ABI metadata. Validation: - native kernel unit suite: 1,491 passed - ABI snapshot and generated bindings check - git diff --check (cherry picked from commit 3b470d3)
Windows does not expose a POSIX permission model through Node. Native entries carry no owner/group/other split or directory search bit, so a guest that drops privileges cannot traverse or write the host-backed sandbox it was given. On Windows only, represent writable host directories as 0777, read-only directories as 0555, writable files as 0666, and read-only files as 0444. Preserve native type bits and let guest chmod and chown metadata override the synthesized permissions. POSIX hosts keep their native modes unchanged. The ABI 43 forward-port performs synthesis only after exact conversion of the native BigInt mode. Existing EOVERFLOW checks for modes, links, sizes, and timestamps remain intact. Validation: - host declaration generation and typechecking - native-metadata and Node uid/gid suites: 15 passed - Windows host execution was not available on this macOS worktree - git diff --check Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> (cherry picked from commit aa12186)
A new git worktree (and a fresh checkout) does not inherit git submodules, a musl sysroot, node_modules, or fetched test binaries, so Vitest and the conformance/browser suites cannot run until those are built or fetched. Agents were treating this as "cannot validate" rather than a setup step. Document the exact sequence in validation.md and build-docs-and-prs.md: submodule init (with the stray-libc/musl recovery), build-musl.sh (sysroot), build.sh (kernel wasm → local-binaries/kernel.wasm + rootfs), root + host `npm ci` (root provides tsx for the conformance runners), and fetch-binaries.sh. Add the explicit instruction not to report "I can't run Vitest/conformance/browser" because a fresh worktree lacks artifacts — build or fetch them and report the real result, or name the exact step that failed. Verified by running the sequence end-to-end in a fresh worktree: kernel wasm + sysroot + rootfs build, `vitest` (778 pass; the only failures were a missing fetched `programs/wasm64/hello64.wasm`), and Sortix conformance (10/10) all ran. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> (cherry picked from commit a3739a2) This conceptual commit combines recovery commits cda80003f and 050a7875e.
Make Area: Purpose the repository convention for PR titles and commit subjects. Add contract-oriented examples and guidance for choosing one primary prefix for cross-cutting changes. Validation: - VitePress documentation build - git diff --check (cherry picked from commit 60fb395)
Chromium-based user agents also contain AppleWebKit. Treating that token as sufficient enabled WebKit-only post-destroy memory handling in Chrome, Edge, Opera, and Chromium on iOS. Forward-port the predicate into the current shared kernel-owned boot helper and keep a pure user-agent classifier for regression coverage. Exclude Chromium, Chrome on iOS, Edge, Opera, Firefox, and Firefox on iOS while retaining Safari and WebKit. Validation: - browser engine detection test: 1 passed - git diff --check (cherry picked from commit 4cbaf2b)
Mutate the sorted mapping vector in place instead of draining and rebuilding it for every munmap call. Preserve the current ABI 43 page-rounding behavior and retain the vector allocation when entries are removed. Keep the original kernel-trap syscall-ring diagnostic while adapting it to the current fatal-entry and blocking-retry cleanup paths. Validated with: scripts/dev-shell.sh -- scripts/ci-run-test-suite.sh cargo-kernel scripts/dev-shell.sh -- npm --prefix host run typecheck End-to-end performance has not been measured yet; that remains part of the batched Node and browser validation. (cherry picked from commit 18a5aa3)
(cherry picked from commit 076362b)
POSIX loopback is machine-scoped. Kandelo previously searched only the sender process socket arena, so an unconnected sendto could report success while dropping the datagram and a connected socket could retain a false ECONNREFUSED. Capture an owned route after the process-local send, release the direct process-table borrows, and then deliver to one accepting foreign endpoint. This preserves sender metadata, avoids duplicate delivery across inherited or SO_REUSEADDR bindings, and clears the provisional connected-socket error only after successful foreign delivery. This changes no ABI exports, imports, or repr(C) layouts. Validated with: scripts/dev-shell.sh -- scripts/ci-run-test-suite.sh cargo-kernel scripts/dev-shell.sh -- bash scripts/check-abi-version.sh scripts/dev-shell.sh -- npm run docs:build (cherry picked from commit c413bd8) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Following stat and fstatat calls on /dev/fd/N and the standard-stream aliases now return the referenced descriptor’s authoritative metadata. No-follow calls report stable devfs symlink metadata, readlink exposes the alias target, and O_NOFOLLOW rejects the final symlink. Keep devfs directory, getdents, and lstat device/inode metadata coherent. Add a guest regression exercised through NodeKernelHost and BrowserKernel. The browser test uses the current minimal runner so it does not activate unrelated shell-package generations. This fixes GNU coreutils mistaking /dev/null for stdin without changing the ABI. (cherry picked from commit 35f0455)
Place Kandelo syscall glue and the C runtime startup object before user link inputs, preserve the caller source, archive, and library order, and keep the final musl archive last. This prevents an explicit -lc from resolving syscall definitions before the platform overrides and avoids scanning dependency libraries before their consumers. Adapt the original change to the current prepared-linker and reproducible path logic. The Kandelo-native driver already uses the same order. (cherry picked from commit 915a84b)
Open the replacement iterator before retiring the active stream, and keep the old state authoritative if opening or closing the replacement sequence fails. Add kernel failure coverage and shared host-bridge coverage for throwing close calls and numeric handle reuse. Adapt the host tests to the current Rust-lent destination capability instead of bypassing private state. (cherry picked from commit e96c381)
Mounts now ignore set-ID bits unless a read-only internal product backend proves immutable open-handle generation identity. Invalid trusted requests fail during mount construction, and Node and browser report ST_NOSUID through the shared VFS path. Add the ABI-owned flag binding and a proposal-only kernel helper so the later target-aware exec transaction can compute credentials without granting them in this task.
Copy the reviewed login and sudo-family bottle members into fresh, root-owned regular inodes on the private Task 6 product backend. Keep the ordinary bottle tree writable and nosuid, and reject the complete projection group on inventory, digest, alias, ownership, or inode identity drift. Wire opaque product-owned policy through build-time images and runtime Node/browser composition without granting credentials.
Keep one generation-safe login lifecycle per logical browser PTY. New demo terminals preauthenticate maker once, then restart ordinary login with bounded backoff while UI reattachment preserves the guest process. Require the exact canonical password hash and autologin message before selecting that policy, and cover fake-clock plus real Chromium, Firefox, and WebKit lifecycles.
Combine the reviewed product contract and its CI staging interface into one purpose-led change. GitHub CI, not this worktree, owns Formula bottle execution and product evidence.
Bind the final VFS, credential, memory-revalidation, and readiness evidence to the ABI 43 vfork contract.
brandonpayton
force-pushed
the
integration/abi43-batch-linear-20260801
branch
from
August 12, 2026 18:22
f59381e to
5669d27
Compare
Merge current main into the ABI 43 batch so the exact staging route uses\nthe protected request, source-test, product-evidence, and Pages contracts.\n\nPreserve the ABI batch's active-ABI flat-shell checks while restoring the\nshared prepared-workspace activation and current product change scope.
Regenerate the authoritative program index after the ABI 43 bump so exact\nruntime builds resolve current package cache keys. Refresh the protected\nrequest-policy digest that binds that index.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Kandelo needs one coherent ABI 43 transition instead of merging many
overlapping ABI, kernel, libc, host, package, and fork-instrument
changes independently. The working integration tip had 176 commits,
including many fixups and generated refreshes. That tree was useful for
recovery, but not a reasonable permanent history.
This batch preserves the accepted platform work as 73 purpose-scoped
commits. It also replaces full-memory copying for eligible
fork-then-exec workloads with genuine shared-memory
vfork()semantics.Pristine upstream CRuby can therefore select its own
vfork()pathwithout the temporary source patch in PR #1166.
Merge method
REBASE MERGE ONLY. DO NOT SQUASH. DO NOT CREATE A MERGE COMMIT.
The 73 commits are intentional review, attribution, and bisection
boundaries. Squashing this PR would destroy those boundaries and violate
the batch contract. The
batched-changeslabel is applied so mergepreparation selects the rebase path.
After the rebase lands on
main, the batched source PRs can be closedas superseded. Do not close them based only on this PR being opened.
What changed
ABI 43 and host ownership
references in fresh workers.
bounded, generated, kernel-owned scratch and scalar contracts.
cleanup, procfs, readiness, and VFS metadata authority into Rust.
package, fixture, and artifact projections.
Affordable fork and genuine vfork
EAGAINbefore allocation orcopying when exact retired-memory debt reaches its bound. Admitted
ordinary forks retain independent copied address spaces.
evidence, and keeps the time-based retirement fallback bounded.
retirement.
allowing a child to overwrite parent continuation state.
kernel_forkto take an explicit ordinary-fork or vfork mode.A separate
kernel_vforkimport, guest marker, and new frame fieldwere rejected because they add implicit state or duplicate call
graphs. The incompatible import, kernel export, host launch metadata,
and instrumented replay contract are versioned together as ABI 43.
SharedArrayBuffer-backedWebAssembly.Memory, with child-privatesyscall, replay-workspace, and continuation-control state.
_exit(),or exact fatal-child containment. Failed exec keeps the lifetime
coherent. Other parent pthread workers remain independently runnable.
signals, traps, credentials, cwd, process groups, descriptors, shared
open file descriptions, wait/reaping, and active side modules.
vfork as uid 1000 and retains its intentional privileged ordinary-fork
fallback.
Other selected platform work
CI, dependency, audio, package, and documentation changes listed
below.
ABI-bound fixture ownership.
stay explicit, while flat VFS names and identities are bound to their
ABI.
Batched source PRs
This PR incorporates the selected work from every item below. Original
authors are retained in the conceptual commits.
munmap()mapping-vector churn under SQLite pressure.already closed; its selected changes remain in this batch.
/dev/dspPCM playback and consumers.a draft source stack and is incorporated here for the coordinated
ABI.
source stack and is incorporated here for the coordinated ABI.
The batch also contains the Kandelo-owned ordinary-fork admission,
shared-memory replay, genuine vfork, upstream Ruby, ABI projection,
validation, and Homebrew ABI-boundary integration described above.
Conceptual commit inventory
73 commits that must be retained by rebase
History and attribution
8c19f577dcb2ef23855e4f5015847674fdd0d2b9onmain.7885a97ac78d5dc70612dd03dd69a1e43c47805c.tree
2e3c97b1dff54356cd4ae319ae5532db42269f5b.d118ec2f887c01a16059f53b25b8ed7713f15016fe3b11cb022d8a8cd648bb1e.commits, and one mho22 commit. Co-author trailers remain attached.
count, or individual pre-consolidation hash are historical
checkpoints. This 73-commit inventory supersedes those history-only
details; their measured tree and runtime evidence remains applicable.
Performance evidence and known risk
The component RSS harness shows why shared memory is the selected design
for a 256 MiB sparse parent:
instead of about 35 ms for the full clone.
This is component evidence, not a Homebrew application RSS claim.
The batch also has a measured startup regression. A same-day pre-batch
build was 37 to 50 percent faster across four Node lifecycle metrics.
Empty-VFS measurements attribute roughly 39 to 42 percent slowdown to
the pre-vfork ABI 43 checkpoint, with vfork adding about 2.3 to 2.4
percent. The commits stay separate so that regression remains
bisectable. This PR makes no broad no-regression claim.
See
docs/measurements/2026-07-31-affordable-fork-then-exec.mdfor the complete design, measurements, rejected alternatives, and
evidence.
Validation
Fresh validation on the exact PR tree used
scripts/dev-shell.sh:bash scripts/check-abi-version.shpassed native, wasm32, and wasm64layouts; kernel exports; generated C and TypeScript bindings; the
snapshot; and the ABI 42-to-43 bump.
bash scripts/ci-run-test-suite.sh cargo-workspacepassed, including1,522 kernel tests, four pointer-contract tests, 13 root-spill tests,
48 shared-ABI tests, fork-instrument tests, and documentation tests.
bash scripts/ci-run-test-suite.sh cargo-xtaskpassed 647 unit tests,one cache-root integration test, and two source-root integration
tests.
bash scripts/ci-run-test-suite.sh vitestpassed 352 files andskipped 28; it recorded 4,307 passes, two expected failures, and 129
skips.
Its isolated upstream Ruby failed-exec, successful-exec, and
privileged-fallback cases each passed, and its teardown supplement
passed three tests.
and WebKit: 19 passed and two intentional cross-engine skips.
git diff-tree --check; the range has no merge,empty, or non-purpose-prefixed commits.
The committed measurement record also contains prior full libc, POSIX,
and Sortix runs after the runtime and vfork tree was complete and before
the final package and Homebrew metadata refreshes: libc 303 passed with
zero failures, POSIX 174 passed with zero failures, and Sortix 5,037
passed with zero failures. Expected failures and skips are itemized in
that document.
Remaining release gates
Opening this PR does not publish ABI 43 artifacts or merge any subsystem
change.
Candidate-ABI Homebrew bottle staging is being developed separately on
emdash/homebrew-complete-qk044and remains a prerequisite forpublication.
Before declaring PR #1166 fully retired in released products, rebuild
and publish the exact pristine upstream Ruby and complete ABI 43 package
closure, construct the Homebrew image, and repeat the real in-guest
tap/install lifecycle with process-tree RSS evidence, no renderer loss,
and no unbounded memory growth. The full product browser and application
benchmark matrices must also run against that published closure without
an ABI 42 fallback.