Skip to content

Commit 7134d49

Browse files
benjamingrdanielleadams
authored andcommitted
child_process: clean event listener correctly
I was working on AbortSignal for spawn and noticed there is a leak in the current code for AbortSignal support in child_process since it removes the wrong listener. I used the new signal as argument feature to make removing the listener easier and added a test. PR-URL: #36424 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Rich Trott <[email protected]>
1 parent 63091f8 commit 7134d49

File tree

2 files changed

+15
-5
lines changed

2 files changed

+15
-5
lines changed

lib/child_process.js

+4-5
Original file line numberDiff line numberDiff line change
@@ -378,14 +378,13 @@ function execFile(file /* , args, options, callback */) {
378378
if (options.signal.aborted) {
379379
process.nextTick(() => kill());
380380
} else {
381+
const childController = new AbortController();
381382
options.signal.addEventListener('abort', () => {
382-
if (!ex) {
383+
if (!ex)
383384
ex = new AbortError();
384-
}
385385
kill();
386-
});
387-
const remove = () => options.signal.removeEventListener('abort', kill);
388-
child.once('close', remove);
386+
}, { signal: childController.signal });
387+
child.once('close', () => childController.abort());
389388
}
390389
}
391390

test/parallel/test-child-process-execfile.js

+11
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
const common = require('../common');
44
const assert = require('assert');
55
const execFile = require('child_process').execFile;
6+
const { getEventListeners } = require('events');
67
const { getSystemErrorName } = require('util');
78
const fixtures = require('../common/fixtures');
89

@@ -68,5 +69,15 @@ const execOpts = { encoding: 'utf8', shell: true };
6869

6970
execFile(process.execPath, [echoFixture, 0], { signal: 'hello' }, callback);
7071
}, { code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError' });
72+
}
73+
{
74+
// Verify that the process completing removes the abort listener
75+
const ac = new AbortController();
76+
const { signal } = ac;
7177

78+
const callback = common.mustCall((err) => {
79+
assert.strictEqual(getEventListeners(ac.signal).length, 0);
80+
assert.strictEqual(err, null);
81+
});
82+
execFile(process.execPath, [fixture, 0], { signal }, callback);
7283
}

0 commit comments

Comments
 (0)