console: don't swallow call stack exceeded errors

Fixes test/parallel/test-console-no-swallow-stack-exceeded.js

PR-URL: https://github.com/nodejs/node/pull/19423
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
This commit is contained in:
Dan Kaplun 2018-03-18 00:36:53 -04:00 committed by Trivikram
parent cde98ce147
commit d49661bb80
3 changed files with 45 additions and 12 deletions

View File

@ -21,15 +21,16 @@
'use strict';
const { ERR_CONSOLE_WRITABLE_STREAM } = require('internal/errors').codes;
const {
isStackOverflowError,
codes: { ERR_CONSOLE_WRITABLE_STREAM },
} = require('internal/errors');
const util = require('util');
const kCounts = Symbol('counts');
// Track amount of indentation required via `console.group()`.
const kGroupIndent = Symbol('groupIndent');
let MAX_STACK_MESSAGE;
function Console(stdout, stderr, ignoreErrors = true) {
if (!(this instanceof Console)) {
return new Console(stdout, stderr, ignoreErrors);
@ -113,17 +114,9 @@ function write(ignoreErrors, stream, string, errorhandler, groupIndent) {
stream.write(string, errorhandler);
} catch (e) {
if (MAX_STACK_MESSAGE === undefined) {
try {
// eslint-disable-next-line no-unused-vars
function a() { a(); }
} catch (err) {
MAX_STACK_MESSAGE = err.message;
}
}
// console is a debugging utility, so it swallowing errors is not desirable
// even in edge cases such as low stack space.
if (e.message === MAX_STACK_MESSAGE && e.name === 'RangeError')
if (isStackOverflowError(e))
throw e;
// Sorry, there's no proper way to pass along the error here.
} finally {

View File

@ -569,11 +569,33 @@ function dnsException(err, syscall, hostname) {
return ex;
}
let MAX_STACK_MESSAGE;
/**
* Returns true if `err` is a `RangeError` with an engine-specific message.
* "Maximum call stack size exceeded" in V8.
*
* @param {Error} err
* @returns {boolean}
*/
function isStackOverflowError(err) {
if (MAX_STACK_MESSAGE === undefined) {
try {
function overflowStack() { overflowStack(); }
overflowStack();
} catch (err) {
MAX_STACK_MESSAGE = err.message;
}
}
return err.name === 'RangeError' && err.message === MAX_STACK_MESSAGE;
}
module.exports = exports = {
dnsException,
errnoException,
exceptionWithHostPort,
uvException,
isStackOverflowError,
message,
AssertionError,
SystemError,

View File

@ -0,0 +1,18 @@
'use strict';
const common = require('../common');
const { Console } = require('console');
const { Writable } = require('stream');
for (const method of ['dir', 'log', 'warn']) {
common.expectsError(() => {
const out = new Writable({
write: common.mustCall(function write(...args) {
// Exceeds call stack.
return write(...args);
}),
});
const c = new Console(out, out, true);
c[method]('Hello, world!');
}, { name: 'RangeError' });
}