fix: close kqueue fd in SetupExitCallback on macOS
Merged
CO
5mo ago+32+32+01234567890123456789-0-0-0123456789
Closes https://github.com/microsoft/node-pty/issues/907
On macOS, SetupExitCallback opens a kqueue() per spawned pty to wait on NOTE_EXIT, but never closes it before the watcher thread returns. This leaks one kqueue file descriptor per pty.spawn() for the lifetime of the host process.
Repro:
const pty = require('node-pty');
const { execSync } = require('child_process');
const kq = () => execSync(`lsof -p ${process.pid} | grep -c KQUEUE`, {encoding:'utf8'}).trim();
(async () => {
console.log('baseline KQUEUE=' + kq());
for (let i = 0; i < 20; i++) {
const p = pty.spawn('/bin/sh', [], { name: 'xterm', cols: 80, rows: 24 });
await new Promise(r => { p.onExit(r); setTimeout(() => p.kill(), 50); });
}
await new Promise(r => setTimeout(r, 500));
console.log('after 20 cycles KQUEUE=' + kq()); // baseline + 20
})();
The Chromium reference this code is based on (kill_mac.cc) closes the kqueue via ScopedFD; the equivalent here is an explicit close(kq) once the kevent wait completes. close(-1) is a harmless EBADF if kqueue() itself failed, so no guard is needed.
Adds a regression test alongside the ptmx leak test from #882.
cc @deepak1556