Skip to content

fix(interpreter): process substitution expands to /dev/fd/63 - #2639

Merged
chaliy merged 1 commit into
mainfrom
claude/procsub-devfd
Oct 8, 2026
Merged

chaliy merged 1 commit into
mainfrom
claude/procsub-devfd

Conversation

@chaliy

@chaliy chaliy commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Requested by Михайло · project thread

What changed

  • <(cmd) / >(cmd) expand to bash's /dev/fd/63, /dev/fd/62, ... (highest free fd counting down from 63, skipping fds already open), restarting per command like bash.
  • The paths live in a per-interpreter fd table (ProcSubFs, a wrapper over the interpreter's view of the filesystem). /dev/fd/N (N ≥ 3) is never passed to the shared VFS, so interpreters sharing one filesystem each have their own /dev/fd/63 (new TM-ISO-028).
  • A substitution reads as its data, stats as a FIFO, and is gone after its command (cat /dev/fd/63 → No such file or directory).
  • Removed the global PROC_SUB_COUNTER and the /dev/fd/proc_sub_<n> files written into the VFS.
  • set -C no longer refuses > >(cmd); exec 3> >(cmd) no longer aborts the script on later writes.

Why

Level-up roadmap, rootfs/OS-shape step: closes the process-substitution-dev-fd bash-oracle gap while keeping tenants isolated in one process.

Before / After (verified)

bash-oracle: match 103 → 104, strict 101 → 102 / 106 (rebased on #2638; floor.txt raised to 104 102). With a coproc open, <(true) skips its fds like bash: 63 60 /dev/fd/62.

echo <(true) <(true) >(true)
diff <(printf 'a\nb\n') <(printf 'a\nc\n'); echo rc=$?
cat /dev/fd/63; echo rc=$?
first line
main /dev/fd/proc_sub_0 /dev/fd/proc_sub_1 /dev/fd/proc_sub_2
bash 5.2 / this branch /dev/fd/63 /dev/fd/62 /dev/fd/61

The diff output, rc=1, and cat: /dev/fd/63: No such file or directory / rc=1 are identical between bash and this branch.

Risk

  • Isolation tests: a recording filesystem shows no /dev/fd path reaching the shared FS; a second interpreter on the same FS can't read, see or write the first's /dev/fd/63; 4 parallel interpreters each read only their own data.
  • Open substitutions are capped by max_file_descriptors. Stack for depth_32_no_stack_overflow is slightly below main.
  • Remaining gaps (limitations.md): a substitution is always its own word (x<(true)); data is buffered, not a live pipe; exec 3> >(cmd) drops fd 3 writes.

Checklist

  • Failing tests first (process_substitution_fd_tests.rs, 14 tests; two bashbox spec cases enabled), verified against bash 5.2
  • fmt, clippy, integration, lib, terminal, CLI, bash_comparison, check-okf
  • knowledge updated (threat-model TM-ISO-028, limitations, log)

Generated by Claude Code

@chaliy chaliy self-assigned this Oct 8, 2026
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
bashkit 5bf22c9 Commit Preview URL

Branch Preview URL
Oct 08 2026, 10:51 AM

`<(cmd)` / `>(cmd)` now expand to bash's `/dev/fd/63`, `/dev/fd/62`, ...
per command, skipping fds still open and reusing 63 once the command (or
the compound command that opened it) finishes.

The data lives in a per-interpreter fd namespace: `ProcSubFs` wraps each
shell's VFS view and answers `/dev/fd/N` (N >= 3) itself, never
forwarding such a path to the shared filesystem, so tenants on one VFS
each get their own `/dev/fd/63` (TM-ISO-028). Replaces the
`/dev/fd/proc_sub_<n>` VFS files and the global counter.

`set -C` no longer refuses `> >(cmd)`. Bash-oracle floor raised to 103 101.
@chaliy
chaliy force-pushed the claude/procsub-devfd branch from 41d7762 to 5bf22c9 Compare October 8, 2026 10:50
@chaliy
chaliy merged commit c3d47a0 into main Oct 8, 2026
49 checks passed
@chaliy
chaliy deleted the claude/procsub-devfd branch October 8, 2026 11:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant