Skip to content

Commit 7b2eefc

Browse files
eduardbmeMylesBorins
authored andcommitted
child_process: spawn ignores options in case args is undefined
spawn method ignores 3-d argument 'options' in case the second one 'args' equals to 'undefined'. Fixes: #24912 PR-URL: #24913 Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Franziska Hinkelmann <franziska.hinkelmann@gmail.com>
1 parent 96bdd47 commit 7b2eefc

4 files changed

+103
-8
lines changed

lib/child_process.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -403,8 +403,9 @@ function normalizeSpawnArguments(file, args, options) {
403403

404404
if (Array.isArray(args)) {
405405
args = args.slice(0);
406-
} else if (args !== undefined &&
407-
(args === null || typeof args !== 'object')) {
406+
} else if (args == null) {
407+
args = [];
408+
} else if (typeof args !== 'object') {
408409
throw new ERR_INVALID_ARG_TYPE('args', 'object', args);
409410
} else {
410411
options = args;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
'use strict';
2+
3+
// This test confirms that `undefined`, `null`, and `[]`
4+
// can be used as a placeholder for the second argument (`args`) of `spawn()`.
5+
// Previously, there was a bug where using `undefined` for the second argument
6+
// caused the third argument (`options`) to be ignored.
7+
// See https://github.com/nodejs/node/issues/24912.
8+
9+
const assert = require('assert');
10+
const { spawn } = require('child_process');
11+
12+
const common = require('../common');
13+
const tmpdir = require('../common/tmpdir');
14+
15+
const command = common.isWindows ? 'cd' : 'pwd';
16+
const options = { cwd: tmpdir.path };
17+
18+
if (common.isWindows) {
19+
// This test is not the case for Windows based systems
20+
// unless the `shell` options equals to `true`
21+
22+
options.shell = true;
23+
}
24+
25+
const testCases = [
26+
undefined,
27+
null,
28+
[],
29+
];
30+
31+
const expectedResult = tmpdir.path.trim().toLowerCase();
32+
33+
(async () => {
34+
const results = await Promise.all(
35+
testCases.map((testCase) => {
36+
return new Promise((resolve) => {
37+
const subprocess = spawn(command, testCase, options);
38+
39+
let accumulatedData = Buffer.alloc(0);
40+
41+
subprocess.stdout.on('data', common.mustCall((data) => {
42+
accumulatedData = Buffer.concat([accumulatedData, data]);
43+
}));
44+
45+
subprocess.stdout.on('end', () => {
46+
resolve(accumulatedData.toString().trim().toLowerCase());
47+
});
48+
});
49+
})
50+
);
51+
52+
assert.deepStrictEqual([...new Set(results)], [expectedResult]);
53+
})();

test/parallel/test-child-process-spawn-typeerror.js

+2-6
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ const invalidArgValueError =
3333
common.expectsError({ code: 'ERR_INVALID_ARG_VALUE', type: TypeError }, 14);
3434

3535
const invalidArgTypeError =
36-
common.expectsError({ code: 'ERR_INVALID_ARG_TYPE', type: TypeError }, 13);
36+
common.expectsError({ code: 'ERR_INVALID_ARG_TYPE', type: TypeError }, 11);
3737

3838
assert.throws(function() {
3939
spawn(invalidcmd, 'this is not an array');
@@ -59,10 +59,6 @@ assert.throws(function() {
5959
spawn(file);
6060
}, invalidArgTypeError);
6161

62-
assert.throws(function() {
63-
spawn(cmd, null);
64-
}, invalidArgTypeError);
65-
6662
assert.throws(function() {
6763
spawn(cmd, true);
6864
}, invalidArgTypeError);
@@ -103,9 +99,9 @@ spawn(cmd, o);
10399

104100
// Variants of undefined as explicit 'no argument' at a position.
105101
spawn(cmd, u, o);
102+
spawn(cmd, n, o);
106103
spawn(cmd, a, u);
107104

108-
assert.throws(function() { spawn(cmd, n, o); }, invalidArgTypeError);
109105
assert.throws(function() { spawn(cmd, a, n); }, invalidArgTypeError);
110106

111107
assert.throws(function() { spawn(cmd, s); }, invalidArgTypeError);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
'use strict';
2+
3+
// This test confirms that `undefined`, `null`, and `[]` can be used
4+
// as a placeholder for the second argument (`args`) of `spawnSync()`.
5+
// Previously, there was a bug where using `undefined` for the second argument
6+
// caused the third argument (`options`) to be ignored.
7+
// See https://github.com/nodejs/node/issues/24912.
8+
9+
const assert = require('assert');
10+
const { spawnSync } = require('child_process');
11+
12+
const common = require('../common');
13+
const tmpdir = require('../common/tmpdir');
14+
15+
const command = common.isWindows ? 'cd' : 'pwd';
16+
const options = { cwd: tmpdir.path };
17+
18+
if (common.isWindows) {
19+
// This test is not the case for Windows based systems
20+
// unless the `shell` options equals to `true`
21+
22+
options.shell = true;
23+
}
24+
25+
const testCases = [
26+
undefined,
27+
null,
28+
[],
29+
];
30+
31+
const expectedResult = tmpdir.path.trim().toLowerCase();
32+
33+
const results = testCases.map((testCase) => {
34+
const { stdout, stderr } = spawnSync(
35+
command,
36+
testCase,
37+
options
38+
);
39+
40+
assert.deepStrictEqual(stderr, Buffer.alloc(0));
41+
42+
return stdout.toString().trim().toLowerCase();
43+
});
44+
45+
assert.deepStrictEqual([...new Set(results)], [expectedResult]);

0 commit comments

Comments
 (0)