fix: prevent PTY file descriptor leak in ShellExecutionService#20916
fix: prevent PTY file descriptor leak in ShellExecutionService#20916stevenelliottjr wants to merge 1 commit intogoogle-gemini:mainfrom
Conversation
…e-gemini#15945) PTY master file descriptors were not being properly closed after process exit or manual kill, leading to system-wide PTY exhaustion on long-running sessions (macOS kern.tty.ptmx_max = 511). Changes: - Add destroyPtyProcess() helper that safely calls destroy() with fallback to kill() for closing PTY master FDs - Add cleanupPtyEntry() helper that destroys PTY, disposes the headless terminal scrollback buffers, and removes the activePtys map entry - Call destroyPtyProcess() immediately in onExit handler to release FDs before waiting for output processing - Dispose headless terminal in finalize() after extracting output, freeing up to 300k-line scrollback buffer memory - Clean up PTY in catch block when spawn succeeds but later initialization (e.g. Terminal construction) throws - Use cleanupPtyEntry() in kill() to properly destroy PTY instead of only deleting the map entry - Hoist ptyProcess declaration outside try block so catch block can access it for cleanup - Remove duplicate activePtys.delete() call in onExit handler Tests: - Add test verifying kill() calls destroy() on PTY process - Add test verifying all resources are cleaned up after normal exit
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request delivers crucial fixes for resource leaks within the shell execution service, specifically targeting PTY (Pseudo-Terminal) processes and their associated headless terminals. By introducing dedicated cleanup functions and refining the lifecycle management of PTYs, it prevents the accumulation of open file descriptors and memory, thereby resolving issues like system-wide PTY exhaustion and memory leaks in long-running sessions. Highlights
Changelog
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request effectively addresses several file descriptor and memory leaks in the ShellExecutionService by introducing robust cleanup mechanisms for PTY processes. The changes are well-structured, with new helper functions for destroying PTYs and cleaning up associated resources. The fixes cover normal exit, manual kill, and error paths during initialization. The added tests correctly verify the new cleanup logic. I've found one critical issue where a resource leak could still occur, and I've provided a suggestion to fix it.
|
Hi @stevenelliottjr, this PR is being closed due to merge conflicts and 29 days of inactivity. To keep the review queue manageable, we are closing stale blocked PRs. Please feel free to re-open this PR or open a new one once the issues are resolved! Thank you for your contribution. |
Summary
Fixes #15945
PTY master file descriptors were not being properly closed after process exit or manual kill, leading to system-wide PTY exhaustion on long-running sessions (macOS
kern.tty.ptmx_max= 511).Root causes identified and fixed:
destroy()never called on PTY process — TheonExithandler deleted the map entry and attempted optional-chaineddestroy?.(), but this was fragile and insufficient. Replaced with a dedicateddestroyPtyProcess()helper that safely callsdestroy()with fallback tokill().headlessTerminal.dispose()never called — The@xterm/headlessTerminal with up to 300,000-line scrollback buffer was never disposed, leaking significant memory per execution. Addeddispose()call infinalize()after output extraction.kill()method only deleted map entry — When a user manually kills a process, the PTY's master FD was never closed. Now usescleanupPtyEntry()to properly destroy the PTY and dispose the terminal.Error path leaked FDs — If
ptyInfo.module.spawn()succeeded but a later step (e.g.Terminalconstruction) threw, the spawned PTY was unreachable. HoistedptyProcessdeclaration outside the try block and added cleanup in the catch block.Duplicate
activePtys.delete()call — Removed the redundant first delete inonExit(the second one infinalize()is the correct location, after output is extracted).Changes:
destroyPtyProcess()— safely destroys a PTY to release its master FDcleanupPtyEntry()— destroys PTY + disposes terminal + removes map entryonExitbefore waiting for output processingfinalize()after extracting outputcleanupPtyEntry()inkill()instead of bare map deleteTest plan
kill()callsdestroy()on PTY process and clearsactivePtys/dev/ptmxFD count stays stablelsof -c node | grep ptmx | wc -ldoesn't grow unbounded