Skip to content

fix: pick up the ghostty TempDir descriptor-leak fix - #288

Merged
arzafran merged 2 commits into
mainfrom
fix/ghostty-tempdir-fd-leak
Aug 11, 2026
Merged

fix: pick up the ghostty TempDir descriptor-leak fix#288
arzafran merged 2 commits into
mainfrom
fix/ghostty-tempdir-fd-leak

Conversation

@arzafran

Copy link
Copy Markdown
Member

What this does

Stops Programa leaking file descriptors while it runs. Long sessions with agents working in panes were accumulating open handles on the temp directory at roughly one every five seconds, climbing toward the per-process limit. Nothing user-visible until you hit that ceiling, at which point the app can no longer open files or accept connections.

Closes #274.

Summary

Bumps the ghostty submodule by exactly one commit, onto darkroomengineering/ghostty#1.

TempDir.init opens two directory handles: one on the directory it creates and one on the system temp directory it creates it in. deinit only ever closed the first. Surface.writeScreenFile compounds it by guarding cleanup with errdefer rather than defer (on success the file must outlive the call, since the path is handed to the pty), so its success path released neither handle.

Upstream never felt this because write_screen_file is a keybinding a user presses occasionally. We drive the same action every five seconds from SessionWALStore's frame capture (frameCaptureCheckInterval), which is what turns it into a steady leak.

Evidence

sudo fs_usage -w -f filesys <pid> on a live Release session, one group per ~5 s:

openat  F=1087  [-2]/private/var/folders/.../T                                  ← leaked
open    F=1089  /private/var/folders/.../T/NKQcy-tUoNk2pYlUU28oRA/screen.txt

lsof confirmed the growth is entirely TMPDIR-root handles: DIR total 1191 / TMPDIR root 593, and 30 s later 1196 / 596. Directory names are 22-char base64 over ghostty's custom -_ alphabet and screen.txt is exactly what writeScreenFile's bufPrint produces, so the attribution is not circumstantial.

Note on the pointer

Deliberately pinned to the fix commit rather than the fork's main, which is 1782 commits ahead of our current pin. This keeps the change a one-commit delta instead of a wholesale ghostty upgrade. Reconciling those lineages is #185.

Test plan

  • zig build -Demit-xcframework=true -Dxcframework-target=native succeeds on the submodule commit
  • CI green, including the GhosttyKit rebuild the bare ghostty path filter triggers
  • lsof -p <pid> | awk '$5=="DIR"' | grep -c '/T$' stays flat (±2) over 30 minutes of agent activity, where it previously grew about one per five seconds

Bumps the ghostty pointer by exactly one commit, onto the fork's
`fix(os): close the parent directory handle in TempDir`.

`TempDir.init` opens two directory handles, one on the directory it creates
and one on the system temp directory it creates it in. `deinit` only closed
the first, and `Surface.writeScreenFile` guards its cleanup with `errdefer`
rather than `defer` (on success the file has to outlive the call, since the
path is handed to the pty), so its success path released neither.

We call that path every five seconds from `SessionWALStore`'s frame capture,
which turned an upstream wart nobody notices into a steady leak: measured
live at roughly 600 descriptors held on the temp directory after two hours,
growing about one per five seconds toward the process limit. Closes #274.
download-prebuilt-ghosttykit.sh verifies the published xcframework against a
checksum pinned per ghostty SHA. A pointer bump without a matching entry falls
through to the source-build fallback, which then fails on the runner while
linking zig's own build runner against libSystem.

The release the Build GhosttyKit workflow published for this SHA exists and is
correct; only the pin was missing.
@arzafran
arzafran merged commit d4cb648 into main Aug 11, 2026
11 checks passed
@arzafran
arzafran deleted the fix/ghostty-tempdir-fd-leak branch August 11, 2026 18:22
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.

fd leak: directory fds on $TMPDIR grow ~1 per 20s, unattributed (1273 open after 2h)

1 participant