From 89f2e204af7255a8e7a59034fa05d8f9b68067e0 Mon Sep 17 00:00:00 2001 From: Matthew Rayermann Date: Fri, 6 Feb 2026 11:07:45 -0800 Subject: [PATCH] fix: add try/catch around getConsoleProcessList in conpty_console_list_agent The conpty_console_list_agent.js is forked as a child process to call Win32 AttachConsole and retrieve the console process list for a given shell PID. When the shell process has already exited, AttachConsole fails and throws an unhandled Error, crashing the forked process. In environments like Vitest that monitor child process exits, this crash surfaces as an unhandled error that fails the entire test run even when all tests pass. This adds a try/catch that falls back to returning just the shell PID (matching the existing timeout fallback behavior in windowsPtyAgent.ts) when AttachConsole fails. Also adds a test that verifies the agent handles a dead PID gracefully. --- src/conpty_console_list_agent.test.ts | 31 +++++++++++++++++++++++++++ src/conpty_console_list_agent.ts | 11 ++++++++-- 2 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 src/conpty_console_list_agent.test.ts diff --git a/src/conpty_console_list_agent.test.ts b/src/conpty_console_list_agent.test.ts new file mode 100644 index 00000000..daaf8f04 --- /dev/null +++ b/src/conpty_console_list_agent.test.ts @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2024, Microsoft Corporation (MIT License). + */ + +import * as assert from 'assert'; +import * as path from 'path'; +import { fork } from 'child_process'; + +if (process.platform === 'win32') { + describe('conpty_console_list_agent', () => { + it('should gracefully handle AttachConsole failure for a dead PID', (done) => { + const agentPath = path.join(__dirname, 'conpty_console_list_agent'); + const deadPid = 999999; + + const agent = fork(agentPath, [deadPid.toString()]); + + agent.on('message', (message: { consoleProcessList: number[] }) => { + // When AttachConsole fails, the agent should fall back to returning + // just the shell PID rather than crashing. + assert.deepStrictEqual(message.consoleProcessList, [deadPid]); + done(); + }); + + agent.on('exit', (code) => { + if (code !== 0) { + done(new Error(`Agent exited with code ${code}, expected graceful fallback`)); + } + }); + }); + }); +} diff --git a/src/conpty_console_list_agent.ts b/src/conpty_console_list_agent.ts index 181ccabb..76ffa285 100644 --- a/src/conpty_console_list_agent.ts +++ b/src/conpty_console_list_agent.ts @@ -10,6 +10,13 @@ import { loadNativeModule } from './utils'; const getConsoleProcessList = loadNativeModule('conpty_console_list').module.getConsoleProcessList; const shellPid = parseInt(process.argv[2], 10); -const consoleProcessList = getConsoleProcessList(shellPid); -process.send!({ consoleProcessList }); +try { + const consoleProcessList = getConsoleProcessList(shellPid); + process.send!({ consoleProcessList }); +} catch { + // AttachConsole can fail if the shell process has already exited. + // Fall back to returning just the shell PID, matching the timeout + // fallback behavior in windowsPtyAgent.ts. + process.send!({ consoleProcessList: [shellPid] }); +} process.exit(0);