Skip to content

fix(chrome): stop unbounded PTY memory growth and Windows ConPTY freezes - #85

Draft
StephenSHorton wants to merge 1 commit into
archive/glass-chromefrom
cursor/suzuri-memory-windows-freeze-8321
Draft

StephenSHorton wants to merge 1 commit into
archive/glass-chromefrom
cursor/suzuri-memory-windows-freeze-8321

Conversation

@StephenSHorton

Copy link
Copy Markdown
Owner

The macOS OOM and the Windows freeze/crash share one primary cause in the Rust chrome host, plus a Windows-only ConPTY hazard.

Root causes

  1. Unbounded PTY queue (macOS OOM, Windows freeze)
    The reader thread used mpsc::channel with no cap and try_read drained every queued chunk in one UI wake. A fast child (Grok alt-screen, yes, ConPTY bursts) could allocate without bound while the UI was busy painting per-cell glyphon text. Memory grew until the Mac died; on Windows the same backlog made the event loop look frozen, then the machine could OOM.

  2. Hot ResizePseudoConsole during animated layout (Windows freeze / hard kill)
    sync_grids_to_panes runs on every redraw. Jelly splits change cols/rows every frame and immediately called portable-pty resize. Concurrent ResizePseudoConsole + hot ReadFile is the same class of native death documented in docs/windows-stability-swarm-report.md for the old Go host. The Go session already has a 300ms quiet gate; the Rust chrome path did not.

Secondary bounds that could grow under garbage/TUI streams:

  • DEC 2026 / ConPTY coalesce hold only capped pending while a 2026 frame was open
  • Unterminated CSI ; floods could grow csi_params
  • Rain worker created a new wgpu bind group every encode (Metal staging leak risk)
  • Main renderer never device.poll()’d after present
  • cosmic-text Buffers stayed at the high-water mark after a large TUI

What changed

  • Bounded PTY queue (sync_channel, 128 × 8 KiB ≈ 1 MiB). Reader blocks instead of allocating.
  • Per-wake drain cap (256 KiB) so one frame cannot parse a multi-megabyte burst.
  • Native resize is debounced (50 ms) so animation does not SIGWINCH / ConPTY-resize every frame. On Windows it is also skipped while I/O is newer than 300 ms; the cell grid still reflows immediately.
  • Sync-hold pending always capped at 1 MiB; CSI params capped at 32.
  • Rain bind group reused; wgpu Maintain::Poll after present; glyphon atlas trim every ~2 s; text buffers shrink after a large window.
  • mem_bound + unit tests: 80k-line storm stays ≤ 2000 scrollback rows; PTY/resize/hold/CSI caps.

Verification

  • cargo test --lib --locked — 402 passed (includes mem_bound, PTY policy, CSI flood, scrollback storm).
  • cargo check --locked --bins on Linux.
  • cargo check --locked --lib --target x86_64-pc-windows-gnu — Windows cfg resize-defer path typechecks.

Could not run the GPU window on this VM, so there are no before/after RSS numbers from a live Suzuri session. The 80k-line storm keeps the grid under max_grid_bytes (~5–6 MiB of cells). The old unbounded PTY queue had no ceiling.

Needs real-machine testing

  • macOS: leave Suzuri idle with rain on for a while, then yes / Grok alt-screen. Activity Monitor RSS should plateau (queue ≤ ~1 MiB + 2000-line scrollback), not climb to OOM.
  • Windows: Grok alt-screen + split / window resize under load. Expect no freeze and no process/machine death. Pane may letterbox until the stream is quiet for 300 ms, then ConPTY catches up (same policy as the Go host).

Open issues

The repo has no open GitHub issues. The only open PR is #84 (Rock / OSC 7880), unrelated. The old Windows stability write-up is about the Go ConPTY host; this PR applies the same fail-closed resize idea to the Rust chrome path that actually owns the window now.

Open in Web Open in Cursor 

The reader thread used an unbounded channel and drained every queued
chunk in one UI wake, so a fast child (Grok, yes, ConPTY bursts) could
grow RSS until the machine OOM'd. Native ResizePseudoConsole also ran
on every animated layout frame while ReadFile was hot — the same class
of Windows hard-kill the Go host already gated.

Cap the PTY queue and per-wake drain, debounce/skip Windows resize
while I/O is recent, and keep scrollback / VT hold / CSI params bounded.
Reuse the rain bind group and poll wgpu so Metal staging buffers do not
accumulate. Add mem_bound regression tests.

Co-authored-by: Stephen Horton <StephenSHorton@users.noreply.github.com>
@StephenSHorton
StephenSHorton changed the base branch from main to archive/glass-chrome October 20, 2026 18:36

This branch has not been deployed

No deployments
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