mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-06-14 05:17:18 -07:00
fix(core): harden PTY resize against native crashes (#27496)
This commit is contained in:
committed by
GitHub
parent
5cac7c10fa
commit
bd53951dc8
@@ -21,9 +21,12 @@ import {
|
|||||||
// Tracking bug: https://github.com/microsoft/node-pty/issues/827
|
// Tracking bug: https://github.com/microsoft/node-pty/issues/827
|
||||||
process.on('uncaughtException', (error) => {
|
process.on('uncaughtException', (error) => {
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
|
const message = error.message || '';
|
||||||
const isPtyResizeError =
|
const isPtyResizeError =
|
||||||
error.message === 'Cannot resize a pty that has already exited';
|
message === 'Cannot resize a pty that has already exited';
|
||||||
const isEbadfError = error.message.includes('EBADF');
|
const isEbadfError =
|
||||||
|
message.includes('EBADF') ||
|
||||||
|
(error as { code?: string }).code === 'EBADF';
|
||||||
const isFromNodePty =
|
const isFromNodePty =
|
||||||
error.stack?.includes('node-pty') || error.stack?.includes('PtyResize');
|
error.stack?.includes('node-pty') || error.stack?.includes('PtyResize');
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import {
|
|||||||
} from './sandboxManager.js';
|
} from './sandboxManager.js';
|
||||||
import type { SandboxConfig } from '../config/config.js';
|
import type { SandboxConfig } from '../config/config.js';
|
||||||
import { killProcessGroup } from '../utils/process-utils.js';
|
import { killProcessGroup } from '../utils/process-utils.js';
|
||||||
|
import { isNodeError } from '../utils/errors.js';
|
||||||
import {
|
import {
|
||||||
ExecutionLifecycleService,
|
ExecutionLifecycleService,
|
||||||
type ExecutionHandle,
|
type ExecutionHandle,
|
||||||
@@ -1507,31 +1508,45 @@ export class ShellExecutionService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const activePty = this.activePtys.get(pid);
|
const activePty = this.activePtys.get(pid);
|
||||||
if (activePty) {
|
if (!activePty) {
|
||||||
try {
|
return;
|
||||||
activePty.ptyProcess.resize(cols, rows);
|
}
|
||||||
activePty.headlessTerminal.resize(cols, rows);
|
|
||||||
} catch (e) {
|
|
||||||
// Ignore errors if the pty has already exited, which can happen
|
|
||||||
// due to a race condition between the exit event and this call.
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
||||||
const err = e as { code?: string; message?: string };
|
|
||||||
const isEsrch = err.code === 'ESRCH';
|
|
||||||
const isEbadf = err.code === 'EBADF' || err.message?.includes('EBADF');
|
|
||||||
const isWindowsPtyError = err.message?.includes(
|
|
||||||
'Cannot resize a pty that has already exited',
|
|
||||||
);
|
|
||||||
|
|
||||||
if (isEsrch || isEbadf || isWindowsPtyError) {
|
// Skip Windows: process.kill(pid, 0) is heavy and native errors are catchable there.
|
||||||
// On Unix, we get an ESRCH or EBADF error.
|
if (process.platform !== 'win32') {
|
||||||
// On Windows, we get a message-based error.
|
try {
|
||||||
// In both cases, it's safe to ignore.
|
process.kill(pid, 0);
|
||||||
} else {
|
} catch (e) {
|
||||||
throw e;
|
// Bail only if the process is explicitly confirmed dead (ESRCH).
|
||||||
|
if (isNodeError(e) && e.code === 'ESRCH') {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
activePty.ptyProcess.resize(cols, rows);
|
||||||
|
activePty.headlessTerminal.resize(cols, rows);
|
||||||
|
} catch (e) {
|
||||||
|
// Ignore errors if the pty has already exited, which can happen
|
||||||
|
// due to a race condition between the exit event and this call.
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||||
|
const err = e as { code?: string; message?: string };
|
||||||
|
const isEsrch = err.code === 'ESRCH';
|
||||||
|
const isEbadf = err.code === 'EBADF' || err.message?.includes('EBADF');
|
||||||
|
const isWindowsPtyError = err.message?.includes(
|
||||||
|
'Cannot resize a pty that has already exited',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isEsrch || isEbadf || isWindowsPtyError) {
|
||||||
|
// On Unix, we get an ESRCH or EBADF error.
|
||||||
|
// On Windows, we get a message-based error.
|
||||||
|
// In both cases, it's safe to ignore.
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Force emit the new state after resize
|
// Force emit the new state after resize
|
||||||
if (activePty) {
|
if (activePty) {
|
||||||
const endLine = activePty.headlessTerminal.buffer.active.length;
|
const endLine = activePty.headlessTerminal.buffer.active.length;
|
||||||
|
|||||||
Reference in New Issue
Block a user