diff --git a/src/win/conpty.cc b/src/win/conpty.cc index 931c5362d..ac45e9666 100644 --- a/src/win/conpty.cc +++ b/src/win/conpty.cc @@ -495,7 +495,7 @@ static Napi::Value PtyResize(const Napi::CallbackInfo& info) { std::lock_guard lock(g_ptyHandlesMutex); const pty_baton* handle = get_pty_baton(lock, id); - if (handle != nullptr) { + if (handle != nullptr && handle->hpc != nullptr) { HANDLE hLibrary = LoadConptyDll(info, useConptyDll); bool fLoadedDll = hLibrary != nullptr; if (fLoadedDll) @@ -537,7 +537,7 @@ static Napi::Value PtyClear(const Napi::CallbackInfo& info) { std::lock_guard lock(g_ptyHandlesMutex); const pty_baton* handle = get_pty_baton(lock, id); - if (handle != nullptr) { + if (handle != nullptr && handle->hpc != nullptr) { HANDLE hLibrary = LoadConptyDll(info, useConptyDll); bool fLoadedDll = hLibrary != nullptr; if (fLoadedDll) @@ -577,9 +577,12 @@ static Napi::Value PtyKill(const Napi::CallbackInfo& info) { PFNCLOSEPSEUDOCONSOLE const pfnClosePseudoConsole = (PFNCLOSEPSEUDOCONSOLE)GetProcAddress( (HMODULE)hLibrary, useConptyDll ? "ConptyClosePseudoConsole" : "ClosePseudoConsole"); - if (pfnClosePseudoConsole) + if (pfnClosePseudoConsole && handle->hpc != nullptr) { pfnClosePseudoConsole(handle->hpc); + // The handle stays in ptyHandles until the exit watcher erases it, so + // null hpc to keep a later call from using the closed pseudoconsole. + handle->hpc = nullptr; } } // Defensive: if PtyConnect was never called (or failed before closing the diff --git a/src/windowsTerminal.test.ts b/src/windowsTerminal.test.ts index c76196512..ffccf0a9b 100644 --- a/src/windowsTerminal.test.ts +++ b/src/windowsTerminal.test.ts @@ -101,6 +101,13 @@ if (process.platform === 'win32') { term.on('exit', () => done()); term.kill(); }); + it('should not crash parent process when killed twice', function (done) { + this.timeout(20000); + const term = new WindowsTerminal('cmd.exe', [], { useConptyDll }); + term.on('exit', () => done()); + term.kill(); + term.kill(); + }); it('should kill the process tree', function (done: Mocha.Done): void { this.timeout(20000); const term = new WindowsTerminal('cmd.exe', [], { useConptyDll });