mirror of
https://github.com/stablyai/orca.git
synced 2026-11-14 01:47:24 +00:00
Fix macOS daemon PTY kqueue descriptor leak (#16870)
* fix(daemon): release node-pty kqueue descriptors * test: remove redundant wait from kqueue regression
This commit is contained in:
@@ -367,7 +367,15 @@ index 7b4b9e1f990fbf95b51528bb56dc9717f5b87532..381d59e11bf158d269335c8231b407fc
|
||||
#endif
|
||||
|
||||
/* NSIG - macro for highest signal + 1, should be defined */
|
||||
@@ -228,6 +267,9 @@ Napi::Value PtyGetProc(const Napi::CallbackInfo& info);
|
||||
@@ -169,6 +208,7 @@ void SetupExitCallback(Napi::Env env, Napi::Function cb, pid_t pid) {
|
||||
}
|
||||
}
|
||||
}
|
||||
+ close(kq);
|
||||
#else
|
||||
while (true) {
|
||||
errno = 0;
|
||||
@@ -228,6 +268,9 @@ Napi::Value PtyGetProc(const Napi::CallbackInfo& info);
|
||||
static int
|
||||
pty_nonblock(int);
|
||||
|
||||
@@ -377,7 +385,7 @@ index 7b4b9e1f990fbf95b51528bb56dc9717f5b87532..381d59e11bf158d269335c8231b407fc
|
||||
#if defined(__APPLE__)
|
||||
static char *
|
||||
pty_getproc(int);
|
||||
@@ -237,13 +279,23 @@ pty_getproc(int, char *);
|
||||
@@ -237,13 +280,23 @@ pty_getproc(int, char *);
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) || defined(__OpenBSD__)
|
||||
@@ -402,7 +410,7 @@ index 7b4b9e1f990fbf95b51528bb56dc9717f5b87532..381d59e11bf158d269335c8231b407fc
|
||||
#endif
|
||||
|
||||
struct DelBuf {
|
||||
@@ -345,8 +397,8 @@ Napi::Value PtyFork(const Napi::CallbackInfo& info) {
|
||||
@@ -345,8 +398,8 @@ Napi::Value PtyFork(const Napi::CallbackInfo& info) {
|
||||
term->c_cc[VSTATUS] = 20;
|
||||
#endif
|
||||
|
||||
@@ -413,7 +421,7 @@ index 7b4b9e1f990fbf95b51528bb56dc9717f5b87532..381d59e11bf158d269335c8231b407fc
|
||||
|
||||
// helperPath
|
||||
std::string helper_path = info[9].As<Napi::String>();
|
||||
@@ -367,14 +419,18 @@ Napi::Value PtyFork(const Napi::CallbackInfo& info) {
|
||||
@@ -367,14 +420,18 @@ Napi::Value PtyFork(const Napi::CallbackInfo& info) {
|
||||
argv[i + 3] = strdup(arg.c_str());
|
||||
}
|
||||
|
||||
@@ -436,7 +444,7 @@ index 7b4b9e1f990fbf95b51528bb56dc9717f5b87532..381d59e11bf158d269335c8231b407fc
|
||||
#else
|
||||
int argc = argv_.Length();
|
||||
int argl = argc + 2;
|
||||
@@ -445,6 +501,9 @@ Napi::Value PtyFork(const Napi::CallbackInfo& info) {
|
||||
@@ -445,6 +502,9 @@ Napi::Value PtyFork(const Napi::CallbackInfo& info) {
|
||||
if (pty_nonblock(master) == -1) {
|
||||
throw Napi::Error::New(napiEnv, "Could not set master fd to nonblocking.");
|
||||
}
|
||||
@@ -446,7 +454,7 @@ index 7b4b9e1f990fbf95b51528bb56dc9717f5b87532..381d59e11bf158d269335c8231b407fc
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -586,6 +645,23 @@ pty_nonblock(int fd) {
|
||||
@@ -586,6 +646,23 @@ pty_nonblock(int fd) {
|
||||
return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
||||
}
|
||||
|
||||
@@ -470,7 +478,7 @@ index 7b4b9e1f990fbf95b51528bb56dc9717f5b87532..381d59e11bf158d269335c8231b407fc
|
||||
/**
|
||||
* pty_getproc
|
||||
* Taken from tmux.
|
||||
@@ -684,15 +760,73 @@ pty_getproc(int fd, char *tty) {
|
||||
@@ -684,15 +761,73 @@ pty_getproc(int fd, char *tty) {
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
@@ -546,7 +554,7 @@ index 7b4b9e1f990fbf95b51528bb56dc9717f5b87532..381d59e11bf158d269335c8231b407fc
|
||||
|
||||
for (; count < 3; count++) {
|
||||
low_fds[count] = posix_openpt(O_RDWR);
|
||||
@@ -706,84 +840,499 @@ pty_posix_spawn(char** argv, char** env,
|
||||
@@ -706,84 +841,499 @@ pty_posix_spawn(char** argv, char** env,
|
||||
POSIX_SPAWN_SETSID;
|
||||
*master = posix_openpt(O_RDWR);
|
||||
if (*master == -1) {
|
||||
@@ -1070,7 +1078,7 @@ index 7b4b9e1f990fbf95b51528bb56dc9717f5b87532..381d59e11bf158d269335c8231b407fc
|
||||
/**
|
||||
* Init
|
||||
*/
|
||||
@@ -793,6 +1342,11 @@ Napi::Object init(Napi::Env env, Napi::Object exports) {
|
||||
@@ -793,6 +1343,11 @@ Napi::Object init(Napi::Env env, Napi::Object exports) {
|
||||
exports.Set("open", Napi::Function::New(env, PtyOpen));
|
||||
exports.Set("resize", Napi::Function::New(env, PtyResize));
|
||||
exports.Set("process", Napi::Function::New(env, PtyGetProc));
|
||||
|
||||
Generated
+3
-3
@@ -185,7 +185,7 @@ patchedDependencies:
|
||||
i18next-cli@1.74.2: 2ee32eef742615cd133e1a6940f027deb3723a8430bb7953bba3a6769b0aac47
|
||||
lint-staged@16.4.0: 7333b3837f80a7fbd045964db6d76ba4fc118e49134bdbabb00585b6b7b60673
|
||||
monaco-editor@0.55.1: 53b71f7d8a7c00b76ffdb73ce83d18e31692f193f5fafa6a390e48f5b3fdd636
|
||||
node-pty@1.1.0: f81acb44ac52265a6053af59e60128471f4655de39e64f8c47c916e0dc8c9416
|
||||
node-pty@1.1.0: 98dadd30788d9235a1a28c4596078918f5936bd92804ca529ab1958f1a0fc278
|
||||
oxlint-plugin-anti-slop@0.1.2: c10c871702365a0c2c59e9f1c5fb92df97cae5755d534c0a3d83c6368f6feafe
|
||||
pdfjs-dist@6.3.289: 424fde648e16c965ce45c55bdda49ecb3a4aa992c856900714c841c3f13f8415
|
||||
sprintf-js@1.1.3: 05316a8b01f155fe19a1e0cb4042c81d43d798a76755c407684e1199a18b1e08
|
||||
@@ -234,7 +234,7 @@ importers:
|
||||
version: 3.3.1
|
||||
node-pty:
|
||||
specifier: ^1.1.0
|
||||
version: 1.1.0(patch_hash=f81acb44ac52265a6053af59e60128471f4655de39e64f8c47c916e0dc8c9416)
|
||||
version: 1.1.0(patch_hash=98dadd30788d9235a1a28c4596078918f5936bd92804ca529ab1958f1a0fc278)
|
||||
posthog-node:
|
||||
specifier: ^5.52.5
|
||||
version: 5.52.5
|
||||
@@ -13756,7 +13756,7 @@ snapshots:
|
||||
|
||||
node-int64@0.4.0: {}
|
||||
|
||||
node-pty@1.1.0(patch_hash=f81acb44ac52265a6053af59e60128471f4655de39e64f8c47c916e0dc8c9416):
|
||||
node-pty@1.1.0(patch_hash=98dadd30788d9235a1a28c4596078918f5936bd92804ca529ab1958f1a0fc278):
|
||||
dependencies:
|
||||
node-addon-api: 7.1.1
|
||||
|
||||
|
||||
@@ -18,6 +18,12 @@ function currentOpenFdCount(): number {
|
||||
.filter((line) => line.trim().length > 0).length
|
||||
}
|
||||
|
||||
function currentKqueueFdCount(): number {
|
||||
return execFileSync('lsof', ['-p', String(process.pid)], { encoding: 'utf8' })
|
||||
.split('\n')
|
||||
.filter((line) => line.includes(' KQUEUE ')).length
|
||||
}
|
||||
|
||||
function getExistingSpawnHelper(): string {
|
||||
const helperPath = getNodePtySpawnHelperCandidates().find((candidate) => existsSync(candidate))
|
||||
expect(helperPath).toBeTruthy()
|
||||
@@ -42,6 +48,19 @@ async function spawnExitingPty(index: number): Promise<void> {
|
||||
const describeOnDarwin = process.platform === 'darwin' ? describe : describe.skip
|
||||
|
||||
describeOnDarwin('node-pty macOS spawn fd handling', () => {
|
||||
// Forty serial real shell launches need a 15-second budget.
|
||||
it('releases the child-exit kqueue fd across repeated pty churn', async () => {
|
||||
const before = currentKqueueFdCount()
|
||||
|
||||
for (let i = 0; i < 40; i++) {
|
||||
await spawnExitingPty(i)
|
||||
}
|
||||
|
||||
const after = currentKqueueFdCount()
|
||||
|
||||
expect(after - before).toBe(0)
|
||||
}, 15000)
|
||||
|
||||
it('does not leak revoked slave tty fds across exited pty spawns', async () => {
|
||||
const before = currentRevokedFdCount()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user