From ceb80f415798818a059051537132bba691c68db7 Mon Sep 17 00:00:00 2001 From: kohta ito Date: Mon, 17 Sep 2018 18:19:26 +0900 Subject: [PATCH] doc: fix default maxBuffer size Correctly document the default maxBuffer size for execSync, execFileSync, and spawnSync. It is 200 * 1024, not Infinity. Add tests to verify behaviour is as documented. PR-URL: https://github.com/nodejs/node/pull/22894 Reviewed-By: Sam Roberts --- doc/api/child_process.md | 6 +- ...r.js => test-child-process-exec-maxbuf.js} | 23 +++++ .../test-child-process-execfile-maxbuf.js | 94 +++++++++++++++++++ .../test-child-process-execfilesync-maxbuf.js | 46 +++++++++ .../test-child-process-execsync-maxbuf.js | 37 ++++++++ .../test-child-process-spawnsync-maxbuf.js | 8 ++ 6 files changed, 211 insertions(+), 3 deletions(-) rename test/parallel/{test-child-process-exec-maxBuffer.js => test-child-process-exec-maxbuf.js} (79%) create mode 100644 test/parallel/test-child-process-execfile-maxbuf.js create mode 100644 test/parallel/test-child-process-execfilesync-maxbuf.js create mode 100644 test/parallel/test-child-process-execsync-maxbuf.js diff --git a/doc/api/child_process.md b/doc/api/child_process.md index b2208c006ccaeb..4fdf6d77b3f44e 100644 --- a/doc/api/child_process.md +++ b/doc/api/child_process.md @@ -721,7 +721,7 @@ changes: process will be killed. **Default:** `'SIGTERM'`. * `maxBuffer` {number} Largest amount of data in bytes allowed on stdout or stderr. If exceeded, the child process is terminated. See caveat at - [`maxBuffer` and Unicode][]. **Default:** `200 * 1024`. + [`maxBuffer` and Unicode][]. **Default:** `Infinity`. * `encoding` {string} The encoding used for all stdio inputs and outputs. **Default:** `'buffer'`. * `windowsHide` {boolean} Hide the subprocess console window that would @@ -788,7 +788,7 @@ changes: * `maxBuffer` {number} Largest amount of data in bytes allowed on stdout or stderr. If exceeded, the child process is terminated and any output is truncated. See caveat at [`maxBuffer` and Unicode][]. - **Default:** `200 * 1024`. + **Default:** `Infinity`. * `encoding` {string} The encoding used for all stdio inputs and outputs. **Default:** `'buffer'`. * `windowsHide` {boolean} Hide the subprocess console window that would @@ -852,7 +852,7 @@ changes: * `maxBuffer` {number} Largest amount of data in bytes allowed on stdout or stderr. If exceeded, the child process is terminated and any output is truncated. See caveat at [`maxBuffer` and Unicode][]. - **Default:** `200 * 1024`. + **Default:** `Infinity`. * `encoding` {string} The encoding used for all stdio inputs and outputs. **Default:** `'buffer'`. * `shell` {boolean|string} If `true`, runs `command` inside of a shell. Uses diff --git a/test/parallel/test-child-process-exec-maxBuffer.js b/test/parallel/test-child-process-exec-maxbuf.js similarity index 79% rename from test/parallel/test-child-process-exec-maxBuffer.js rename to test/parallel/test-child-process-exec-maxbuf.js index dfa46b0b000aab..1a47cbee3c2cf1 100644 --- a/test/parallel/test-child-process-exec-maxBuffer.js +++ b/test/parallel/test-child-process-exec-maxbuf.js @@ -10,6 +10,29 @@ function runChecks(err, stdio, streamName, expected) { assert.deepStrictEqual(stdio[streamName], expected); } +// default value +{ + const cmd = `"${process.execPath}" -e "console.log('a'.repeat(200 * 1024))"`; + + cp.exec(cmd, common.mustCall((err) => { + assert(err instanceof RangeError); + assert.strictEqual(err.message, 'stdout maxBuffer length exceeded'); + assert.strictEqual(err.code, 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER'); + })); +} + +// default value +{ + const cmd = + `${process.execPath} -e "console.log('a'.repeat(200 * 1024 - 1))"`; + + cp.exec(cmd, common.mustCall((err, stdout, stderr) => { + assert.ifError(err); + assert.strictEqual(stdout.trim(), 'a'.repeat(200 * 1024 - 1)); + assert.strictEqual(stderr, ''); + })); +} + { const cmd = `"${process.execPath}" -e "console.log('hello world');"`; const options = { maxBuffer: Infinity }; diff --git a/test/parallel/test-child-process-execfile-maxbuf.js b/test/parallel/test-child-process-execfile-maxbuf.js new file mode 100644 index 00000000000000..ba074630a14a6b --- /dev/null +++ b/test/parallel/test-child-process-execfile-maxbuf.js @@ -0,0 +1,94 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const { execFile } = require('child_process'); + +function checkFactory(streamName) { + return common.mustCall((err) => { + assert(err instanceof RangeError); + assert.strictEqual(err.message, `${streamName} maxBuffer length exceeded`); + assert.strictEqual(err.code, 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER'); + }); +} + +// default value +{ + execFile( + process.execPath, + ['-e', 'console.log("a".repeat(200 * 1024))'], + checkFactory('stdout') + ); +} + +// default value +{ + execFile( + process.execPath, + ['-e', 'console.log("a".repeat(200 * 1024 - 1))'], + common.mustCall((err, stdout, stderr) => { + assert.ifError(err); + assert.strictEqual(stdout.trim(), 'a'.repeat(200 * 1024 - 1)); + assert.strictEqual(stderr, ''); + }) + ); +} + +{ + const options = { maxBuffer: Infinity }; + + execFile( + process.execPath, + ['-e', 'console.log("hello world");'], + options, + common.mustCall((err, stdout, stderr) => { + assert.ifError(err); + assert.strictEqual(stdout.trim(), 'hello world'); + assert.strictEqual(stderr, ''); + }) + ); +} + +{ + execFile('echo', ['hello world'], { maxBuffer: 5 }, checkFactory('stdout')); +} + +const unicode = '中文测试'; // length = 4, byte length = 12 + +{ + execFile( + process.execPath, + ['-e', `console.log('${unicode}');`], + { maxBuffer: 10 }, + checkFactory('stdout')); +} + +{ + execFile( + process.execPath, + ['-e', `console.error('${unicode}');`], + { maxBuffer: 10 }, + checkFactory('stderr') + ); +} + +{ + const child = execFile( + process.execPath, + ['-e', `console.log('${unicode}');`], + { encoding: null, maxBuffer: 10 }, + checkFactory('stdout') + ); + + child.stdout.setEncoding('utf-8'); +} + +{ + const child = execFile( + process.execPath, + ['-e', `console.error('${unicode}');`], + { encoding: null, maxBuffer: 10 }, + checkFactory('stderr') + ); + + child.stderr.setEncoding('utf-8'); +} diff --git a/test/parallel/test-child-process-execfilesync-maxbuf.js b/test/parallel/test-child-process-execfilesync-maxbuf.js new file mode 100644 index 00000000000000..7ea7a0645d65cb --- /dev/null +++ b/test/parallel/test-child-process-execfilesync-maxbuf.js @@ -0,0 +1,46 @@ +'use strict'; +require('../common'); + +// This test checks that the maxBuffer option for child_process.spawnSync() +// works as expected. + +const assert = require('assert'); +const execFileSync = require('child_process').execFileSync; +const msgOut = 'this is stdout'; +const msgOutBuf = Buffer.from(`${msgOut}\n`); + +const args = [ + '-e', + `console.log("${msgOut}");` +]; + +// Verify that an error is returned if maxBuffer is surpassed. +{ + assert.throws( + () => execFileSync(process.execPath, args, { maxBuffer: 1 }), + (e) => { + assert.ok(e, 'maxBuffer should error'); + assert.strictEqual(e.errno, 'ENOBUFS'); + assert.deepStrictEqual(e.stdout, msgOutBuf); + return true; + } + ); +} + +// Verify that a maxBuffer size of Infinity works. +{ + const ret = execFileSync(process.execPath, args, { maxBuffer: Infinity }); + + assert.deepStrictEqual(ret, msgOutBuf); +} + +// maxBuffer size is Infinity at default. +{ + const ret = execFileSync( + process.execPath, + ['-e', "console.log('a'.repeat(200 * 1024))"], + { encoding: 'utf-8' } + ); + + assert.ifError(ret.error); +} diff --git a/test/parallel/test-child-process-execsync-maxbuf.js b/test/parallel/test-child-process-execsync-maxbuf.js new file mode 100644 index 00000000000000..0d2fa306939b59 --- /dev/null +++ b/test/parallel/test-child-process-execsync-maxbuf.js @@ -0,0 +1,37 @@ +'use strict'; +require('../common'); + +// This test checks that the maxBuffer option for child_process.spawnSync() +// works as expected. + +const assert = require('assert'); +const { execSync } = require('child_process'); +const msgOut = 'this is stdout'; +const msgOutBuf = Buffer.from(`${msgOut}\n`); + +const args = [ + '-e', + `"console.log('${msgOut}')";` +]; + +// Verify that an error is returned if maxBuffer is surpassed. +{ + assert.throws(() => { + execSync(`"${process.execPath}" ${args.join(' ')}`, { maxBuffer: 1 }); + }, (e) => { + assert.ok(e, 'maxBuffer should error'); + assert.strictEqual(e.errno, 'ENOBUFS'); + assert.deepStrictEqual(e.stdout, msgOutBuf); + return true; + }); +} + +// Verify that a maxBuffer size of Infinity works. +{ + const ret = execSync( + `"${process.execPath}" ${args.join(' ')}`, + { maxBuffer: Infinity } + ); + + assert.deepStrictEqual(ret, msgOutBuf); +} diff --git a/test/parallel/test-child-process-spawnsync-maxbuf.js b/test/parallel/test-child-process-spawnsync-maxbuf.js index 022c090c338d13..aec42b555bcd47 100644 --- a/test/parallel/test-child-process-spawnsync-maxbuf.js +++ b/test/parallel/test-child-process-spawnsync-maxbuf.js @@ -32,3 +32,11 @@ const args = [ assert.ifError(ret.error); assert.deepStrictEqual(ret.stdout, msgOutBuf); } + +// maxBuffer size is Infinity at default. +{ + const args = ['-e', "console.log('a'.repeat(200 * 1024))"]; + const ret = spawnSync(process.execPath, args, { encoding: 'utf-8' }); + + assert.ifError(ret.error); +}