Skip to content

Bound byte-string conversion allocations for large files - #440

Open
MiguelsPizza wants to merge 5 commits into
vercel-labs:mainfrom
WebMCP-org:alex/bounded-byte-conversion
Open

MiguelsPizza wants to merge 5 commits into
vercel-labs:mainfrom
WebMCP-org:alex/bounded-byte-conversion

Conversation

@MiguelsPizza

@MiguelsPizza MiguelsPizza commented Sep 20, 2026

Copy link
Copy Markdown

Converting a large byte buffer concatenates one character at a time, creating enough intermediate string nodes to exhaust Chrome's heap before a small head -c request can return. A 377 MB mounted PDF reproduced the renderer crash.

Convert bytes in bounded 32 KiB batches with Reflect.apply(String.fromCharCode, ...), and reuse that helper for UTF-8 encoding. This preserves byte values, conversion limits, and the existing filesystem and shell behavior. The PR changes three files: the conversion helper, a constrained-heap regression, and a patch changeset.

The regression checks every byte and multibyte UTF-8 output in a child process with a 128 MiB heap; it fails on the original implementation and passes with the fix. In a local Chrome microbenchmark, Reflect.apply takes 67.9 ms for 32 MiB versus 475.3 ms for typed-array spread. The ECMAScript apply operation consumes the typed array as an array-like argument list without its iterator overhead.

Validation: build/typecheck, lint, knip, encoding and distribution regressions pass. The full non-WASM suite has 15,353 passes and 98 skips. Ten failures also reproduce on the unchanged release: two macOS symlink-root cleanup cases and eight unavailable native xz/zstd codec cases. The application consumer is Rook #174.

Converting each byte with string concatenation creates a rope node per byte and exhausts the browser heap before head can return a small slice. Convert in bounded batches and share the same path with UTF-8 pipeline encoding. A constrained-heap child-process regression checks every byte and multibyte text.
@vercel

vercel Bot commented Sep 20, 2026

Copy link
Copy Markdown
Contributor

@MiguelsPizza is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

@auto-maintain

auto-maintain Bot commented Sep 20, 2026

Copy link
Copy Markdown

🤖 auto-maintain review

Automated, advisory triage for @MiguelsPizza's PR. Facts below are read from the GitHub API.

Check Result
Author's merged PRs (this repo) 0 — ⚠️ first-time contributor
Account established ✅ (age 1766d · 119 followers · 61 public repos)
Commits signed/verified ⚠️ 0/5
Changeset included ✅ (.changeset/bounded-byte-conversion.md)

Review panel: 🟢 low highest severity

just-bash maintainer code review: 🟢 low

No actionable defects found in the complete base-to-head diff.

General code review: 🟢 low

No actionable defects found in the complete base-to-head diff.

Adversarial security: 🟢 low

No actionable adversarial security issues found in the base-to-head diff.

Adversarial security (second opinion): 🟢 low

Net diff is limited to chunked Uint8Array-to-latin1 conversion in encoding.ts (plus a changeset and a heap-bounded regression test); the broader streaming/range-read work described in the PR body was reverted by the final commit. The conversion is byte-for-byte equivalent for Uint8Array inputs, the 32768 chunk size stays within engine argument limits, existing size guards are preserved (encodeUtf8ToBytes still asserts before converting), and there are no new network, process-execution, dependency, CI, or filesystem-trust-boundary changes. No actionable security findings.

Standard Bash and host portability: 🟢 low

No actionable Bash or host-portability issues found in the complete diff.

Posted by auto-maintain. This automated code review is advisory; a human maintainer makes the call.

Chrome profiles attribute over 90 percent of the large-file head command to byte-string conversion. Reflect.apply reads each bounded typed-array chunk directly and avoids spread iteration; measured conversion of the 377 MB PDF falls below one second while preserving every byte.
A small head or tail request previously read an entire mounted file, and sequential filters kept processing after a downstream head had enough input. Add an optional byte-range capability through the existing filesystem gates, and use native bounded streams for supported filter pipelines. Each stage keeps isolated shell state while sharing command, memory and output accounting. Preserve the general shell executor and binary decoding fallback for compositions that still require buffering.
@MiguelsPizza MiguelsPizza changed the title Avoid per-byte allocation during binary and UTF-8 conversion Bound large-file reads and stream shell filter pipelines Sep 20, 2026
@vercel-security-reviewer

Copy link
Copy Markdown

Security review details

@auto-maintain

auto-maintain Bot commented Sep 20, 2026

Copy link
Copy Markdown

⚠️ auto-maintain: review severity raised to 🟡 medium

A new push changed this PR and the review now contains a higher-severity finding. See the updated review comment above.

Streaming must not reset grep matcher work or bypass the AWK record ceiling, including records consumed by getline. Share the existing matcher counter and count AWK input as it is consumed.

Keep legacy filesystems working without hiding full-file reads behind a range method: propagate unsupported ranges through mounts, then apply and charge the full-file budget at the command boundary. Preserve reads from zero-size host pseudo-files and document the retained sed input buffer.
Keep the original heap-allocation fix, its constrained-heap regression, and the measured Reflect.apply improvement. Native range reads are maintained separately in the Rook fork; the concurrent pipeline experiment is preserved but removed from this review.
@MiguelsPizza MiguelsPizza changed the title Bound large-file reads and stream shell filter pipelines Bound byte-string conversion allocations for large files Sep 20, 2026
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