Skip to content

fix(runtime): reject zero-progress JS stream writes - #1747

Merged
Lorenzobattistela merged 1 commit into
bendlang:mainfrom
vicmcorrea:fix/js-stream-zero-progress
Oct 19, 2026
Merged

Lorenzobattistela merged 1 commit into
bendlang:mainfrom
vicmcorrea:fix/js-stream-zero-progress

Conversation

@vicmcorrea

@vicmcorrea vicmcorrea commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Problem and fix

The JS runtime's standard-stream writer retries without advancing when fs.writeSync returns zero for nonempty data; repeated zero returns make it spin indefinitely. Reject that result through its existing short-write failure path (exit 1), using the same small guard as the CLI writer in #1691. This extends the zero-progress rule already applied to File.write in #1446.

Blast radius

Five replacement lines in bend2/comp.ts's JS io_out, used by stdout/stderr effects and emitted result output, plus tests/io/stream_write_zero.{bend,js}. Successful writes, positive short writes, EINTR/EAGAIN retries and EPIPE→SIGPIPE behavior retain their existing paths. A nonempty zero-byte host return now fails immediately instead of retrying. Native C and the separate CLI writer are unchanged.

Regression evidence

The JS-only fixture serializes the runtime's actual io_out into bounded children and injects zero returns for stdout and stderr. Source execution and emitted Bun/Node print 1 on main f5cee564 (fails expected 0) and 0 with the fix. Each child has a two-second deadline; the broken fixture stops after its first failed child.

Checks

  • Repository gate: 54/54 with CI-pinned ttok 0.3; comp.ts is 65,541/66,000 tokens. git diff --check and GitHub’s repo-gate check pass.
  • New fixture in source, --checkup imports and emitted Bun/Node. Eight fixtures, including the new regression, pass their applicable local lanes (30 checks).
  • Actual emitted-program controls cover ordinary output, bytewise UTF-8 short writes, EINTR/EAGAIN, empty output and zero after partial progress. Real closed-reader pipes preserve SIGPIPE under Bun and Node.
  • Emitted C for two stdout/pure-result samples is byte-identical before/after.

Validation limits

Zero returns are deliberately injected; no ordinary OS occurrence or prevalence is established. Checked locally on macOS arm64, Bun 1.3.11 and Node 26.8.2. Full cluster tests, Linux runtime tests and GPU checks were not run; GitHub CI ran the repository gate on Linux. The existing file-write and EPIPE foreign fixtures require Bun FFI, so their Node lanes were skipped; separate Node controls cover the changed writer and real EPIPE. C text comparison is limited to two samples; native binaries and a full TypeScript check were not run.

@Lorenzobattistela Lorenzobattistela self-assigned this Oct 19, 2026
@Lorenzobattistela
Lorenzobattistela merged commit 2d1bb19 into bendlang:main Oct 19, 2026
1 check passed
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.

2 participants