Skip to content

Commit

Permalink
console: don't swallow call stack exceeded errors
Browse files Browse the repository at this point in the history
Fixes test/parallel/test-console-no-swallow-stack-exceeded.js

PR-URL: #19423
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
  • Loading branch information
dbkaplun authored and targos committed Mar 27, 2018
1 parent e895d54 commit 6ead99a
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 12 deletions.
17 changes: 5 additions & 12 deletions lib/console.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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 {
Expand Down
22 changes: 22 additions & 0 deletions lib/internal/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -445,10 +445,32 @@ 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,
isStackOverflowError,
message,
Error: makeNodeError(Error),
TypeError: makeNodeError(TypeError),
Expand Down
18 changes: 18 additions & 0 deletions test/parallel/test-console-no-swallow-stack-overflow.js
Original file line number Diff line number Diff line change
@@ -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' });
}

0 comments on commit 6ead99a

Please sign in to comment.