Conversation
…d one A second kill issued before the shell's exit event reaches node-pty's native kill again, which calls ConptyClosePseudoConsole on an already freed pseudo console handle and corrupts the heap (0xc0000374), taking the whole main process down with no JS error. killPty now closes a given pty once; resizePty and writePty skip a pty that was killed. Closes #405
|
Reviewing |
|
Adversarial review at |
…nt it A child node process loads the real node-pty with useConptyDll and kills a pty twice back to back; with the guard removed it dies with 0xc0000374. The ipc-bridge context now records the once-only kill. Refs #405
|
Re-review at |
|
CI at |
…l test On CI node-pty is built into build/Release, which has no conpty/ folder (the afterPack hook adds it at packaging time), so the child could not find conpty.dll. The child now loads a temp copy of node-pty that carries only the prebuilds, the layout the packaged app resolves. Refs #405
|
Re-review at |
Refs #405
Cause
ptyProcess.kill()withuseConptyDllends inConptyClosePseudoConsole(hpc)(node-ptyconpty.ccPtyKill). The native handle is only dropped from node-pty's table when the shell's exit thread runs, so a secondkillissued before the exit event finds the handle still registered and callsClosePseudoConsoleon an already-freed HPCON. That is a double free: STATUS_HEAP_CORRUPTION (0xc0000374) inconpty.dll+0x6126(insideConptyClosePseudoConsole, export at +0x60b0) called fromconpty.nodekill.killPty(pty-ops.js) had no memory of a previous kill;stop-session, the windowclosedhandler andbefore-quitcan all reach it for the same session.Reproduction (isolated instance, throwaway HOME)
Open the panel shell, then
stopSession(id)twice back to back: 5 of 5 runs crashed on the first iteration with the same signature. Same driver and scenario with this change: 5 runs x 8 iterations, 0 crashes. Panel toggle, resize-only, single kill, kill-then-resize and kill-while-streaming did not crash before either (8 iterations each).Change
killPtycloses a given pty once;resizePtyandwritePtydo nothing on a pty that was killed. Unit tests intest/pty-ops.test.js.Integration test
test/pty-ops-conpty-kill.test.jsspawns a child node process with the real node-pty (useConptyDll), callskillPtytwice back to back and asserts the child exits 0. With the guard removed it fails 3 of 3 runs with exit status 3221226356 (0xc0000374); with it, it passes.What is not established
The production double-kill path is not identified; the dumps cannot tell. Candidates: window
closedfollowed bybefore-quit,stop-sessionplus a panel toggle, a doublestop-session. HenceRefs, notCloses.A second, separate race exists upstream: node-pty #922 (merged 2026-05-13, shipped from 1.2.0-beta.13, not in the installed 1.1.0). Not addressed here.