Skip to content

Commit 6ead99a

Browse files
dbkapluntargos
authored andcommitted
console: don't swallow call stack exceeded errors
Fixes test/parallel/test-console-no-swallow-stack-exceeded.js PR-URL: #19423 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Ruben Bridgewater <[email protected]> Reviewed-By: Colin Ihrig <[email protected]>
1 parent e895d54 commit 6ead99a

File tree

3 files changed

+45
-12
lines changed

3 files changed

+45
-12
lines changed

lib/console.js

+5-12
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,16 @@
2121

2222
'use strict';
2323

24-
const { ERR_CONSOLE_WRITABLE_STREAM } = require('internal/errors').codes;
24+
const {
25+
isStackOverflowError,
26+
codes: { ERR_CONSOLE_WRITABLE_STREAM },
27+
} = require('internal/errors');
2528
const util = require('util');
2629
const kCounts = Symbol('counts');
2730

2831
// Track amount of indentation required via `console.group()`.
2932
const kGroupIndent = Symbol('groupIndent');
3033

31-
let MAX_STACK_MESSAGE;
32-
3334
function Console(stdout, stderr, ignoreErrors = true) {
3435
if (!(this instanceof Console)) {
3536
return new Console(stdout, stderr, ignoreErrors);
@@ -113,17 +114,9 @@ function write(ignoreErrors, stream, string, errorhandler, groupIndent) {
113114

114115
stream.write(string, errorhandler);
115116
} catch (e) {
116-
if (MAX_STACK_MESSAGE === undefined) {
117-
try {
118-
// eslint-disable-next-line no-unused-vars
119-
function a() { a(); }
120-
} catch (err) {
121-
MAX_STACK_MESSAGE = err.message;
122-
}
123-
}
124117
// console is a debugging utility, so it swallowing errors is not desirable
125118
// even in edge cases such as low stack space.
126-
if (e.message === MAX_STACK_MESSAGE && e.name === 'RangeError')
119+
if (isStackOverflowError(e))
127120
throw e;
128121
// Sorry, there's no proper way to pass along the error here.
129122
} finally {

lib/internal/errors.js

+22
Original file line numberDiff line numberDiff line change
@@ -445,10 +445,32 @@ function dnsException(err, syscall, hostname) {
445445
return ex;
446446
}
447447

448+
let MAX_STACK_MESSAGE;
449+
/**
450+
* Returns true if `err` is a `RangeError` with an engine-specific message.
451+
* "Maximum call stack size exceeded" in V8.
452+
*
453+
* @param {Error} err
454+
* @returns {boolean}
455+
*/
456+
function isStackOverflowError(err) {
457+
if (MAX_STACK_MESSAGE === undefined) {
458+
try {
459+
function overflowStack() { overflowStack(); }
460+
overflowStack();
461+
} catch (err) {
462+
MAX_STACK_MESSAGE = err.message;
463+
}
464+
}
465+
466+
return err.name === 'RangeError' && err.message === MAX_STACK_MESSAGE;
467+
}
468+
448469
module.exports = exports = {
449470
dnsException,
450471
errnoException,
451472
exceptionWithHostPort,
473+
isStackOverflowError,
452474
message,
453475
Error: makeNodeError(Error),
454476
TypeError: makeNodeError(TypeError),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
'use strict';
2+
const common = require('../common');
3+
const { Console } = require('console');
4+
const { Writable } = require('stream');
5+
6+
for (const method of ['dir', 'log', 'warn']) {
7+
common.expectsError(() => {
8+
const out = new Writable({
9+
write: common.mustCall(function write(...args) {
10+
// Exceeds call stack.
11+
return write(...args);
12+
}),
13+
});
14+
const c = new Console(out, out, true);
15+
16+
c[method]('Hello, world!');
17+
}, { name: 'RangeError' });
18+
}

0 commit comments

Comments
 (0)