From bed0560fb5e7172e71476713042d5f8ba77fdf2e Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Sun, 5 Nov 2017 12:26:27 +0000 Subject: [PATCH] console: avoid adding infinite error listeners If the console destination is a unix pipe (net.Socket), write() is async. If the destination is broken, we are adding an 'error' event listener to avoid a process crash. This PR makes sure that we are adding that listener only once. Fixes: https://github.com/nodejs/node/issues/16767 PR-URL: https://github.com/nodejs/node/pull/16770 Fixes: https://github.com/nodejs/node/issues/16767 Reviewed-By: James M Snell Reviewed-By: Anna Henningsen Reviewed-By: Colin Ihrig Reviewed-By: Anatoli Papirovski Reviewed-By: Luigi Pinca Reviewed-By: Sam Roberts --- lib/console.js | 5 +++- .../test-console-log-stdio-broken-dest.js | 24 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 test/parallel/test-console-log-stdio-broken-dest.js diff --git a/lib/console.js b/lib/console.js index 54c8aba8299565..2304a6668790de 100644 --- a/lib/console.js +++ b/lib/console.js @@ -83,7 +83,10 @@ function createWriteErrorHandler(stream) { // an `error` event. Adding a `once` listener will keep that error // from becoming an uncaught exception, but since the handler is // removed after the event, non-console.* writes won’t be affected. - stream.once('error', noop); + // we are only adding noop if there is no one else listening for 'error' + if (stream.listenerCount('error') === 0) { + stream.on('error', noop); + } } }; } diff --git a/test/parallel/test-console-log-stdio-broken-dest.js b/test/parallel/test-console-log-stdio-broken-dest.js new file mode 100644 index 00000000000000..d29e8ee5173be7 --- /dev/null +++ b/test/parallel/test-console-log-stdio-broken-dest.js @@ -0,0 +1,24 @@ +'use strict'; + +const common = require('../common'); +const { Writable } = require('stream'); +const { Console } = require('console'); +const { EventEmitter } = require('events'); + +const stream = new Writable({ + write(chunk, enc, cb) { + cb(); + }, + writev(chunks, cb) { + setTimeout(cb, 10, new Error('kaboom')); + } +}); +const myConsole = new Console(stream, stream); + +process.on('warning', common.mustNotCall); + +stream.cork(); +for (let i = 0; i < EventEmitter.defaultMaxListeners + 1; i++) { + myConsole.log('a message'); +} +stream.uncork();