util: recover from maximum call stack size
Using util.inspect should still return values in case the maximum call stack size is reached. This is important to inspect linked lists and similar. PR-URL: https://github.com/nodejs/node/pull/20725 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Anatoli Papirovski <apapirovski@mac.com> Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Ali Ijaz Sheikh <ofrobots@google.com> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com> Reviewed-By: Daniel Bevenius <daniel.bevenius@gmail.com> Reviewed-By: Sakthipriyan Vairamani <thechargingvolcano@gmail.com> Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com> Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
parent
43a2091187
commit
b26506b95f
@ -360,6 +360,10 @@ stream.write('With ES6');
|
|||||||
<!-- YAML
|
<!-- YAML
|
||||||
added: v0.3.0
|
added: v0.3.0
|
||||||
changes:
|
changes:
|
||||||
|
- version: REPLACEME
|
||||||
|
pr-url: https://github.com/nodejs/node/pull/REPLACEME
|
||||||
|
description: Inspecting linked lists and similar objects is now possible
|
||||||
|
up to the maximum call stack size.
|
||||||
- version: v10.0.0
|
- version: v10.0.0
|
||||||
pr-url: https://github.com/nodejs/node/pull/19259
|
pr-url: https://github.com/nodejs/node/pull/19259
|
||||||
description: The `WeakMap` and `WeakSet` entries can now be inspected
|
description: The `WeakMap` and `WeakSet` entries can now be inspected
|
||||||
@ -388,8 +392,9 @@ changes:
|
|||||||
properties will be included in the formatted result as well as [`WeakMap`][]
|
properties will be included in the formatted result as well as [`WeakMap`][]
|
||||||
and [`WeakSet`][] entries. **Default:** `false`.
|
and [`WeakSet`][] entries. **Default:** `false`.
|
||||||
* `depth` {number} Specifies the number of times to recurse while formatting
|
* `depth` {number} Specifies the number of times to recurse while formatting
|
||||||
the `object`. This is useful for inspecting large complicated objects.
|
the `object`. This is useful for inspecting large complicated objects. To
|
||||||
To make it recurse indefinitely pass `null`. **Default:** `2`.
|
make it recurse up to the maximum call stack size pass `Infinity` or `null`.
|
||||||
|
**Default:** `2`.
|
||||||
* `colors` {boolean} If `true`, the output will be styled with ANSI color
|
* `colors` {boolean} If `true`, the output will be styled with ANSI color
|
||||||
codes. Colors are customizable, see [Customizing `util.inspect` colors][].
|
codes. Colors are customizable, see [Customizing `util.inspect` colors][].
|
||||||
**Default:** `false`.
|
**Default:** `false`.
|
||||||
|
22
lib/util.js
22
lib/util.js
@ -701,14 +701,32 @@ function formatValue(ctx, value, recurseTimes) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx.seen.push(value);
|
ctx.seen.push(value);
|
||||||
const output = formatter(ctx, value, recurseTimes, keys);
|
let output;
|
||||||
|
// This corresponds to a depth of at least 333 and likely 500.
|
||||||
|
if (ctx.indentationLvl < 1000) {
|
||||||
|
output = formatter(ctx, value, recurseTimes, keys);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
output = formatter(ctx, value, recurseTimes, keys);
|
||||||
|
} catch (err) {
|
||||||
|
if (errors.isStackOverflowError(err)) {
|
||||||
|
ctx.seen.pop();
|
||||||
|
return ctx.stylize(
|
||||||
|
`[${constructor || tag || 'Object'}: Inspection interrupted ` +
|
||||||
|
'prematurely. Maximum call stack size exceeded.]',
|
||||||
|
'special'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (extra !== undefined)
|
if (extra !== undefined)
|
||||||
output.unshift(extra);
|
output.unshift(extra);
|
||||||
|
|
||||||
for (var i = 0; i < symbols.length; i++) {
|
for (var i = 0; i < symbols.length; i++) {
|
||||||
output.push(formatProperty(ctx, value, recurseTimes, symbols[i], 0));
|
output.push(formatProperty(ctx, value, recurseTimes, symbols[i], 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.seen.pop();
|
ctx.seen.pop();
|
||||||
|
|
||||||
return reduceToSingleString(ctx, output, base, braces);
|
return reduceToSingleString(ctx, output, base, braces);
|
||||||
|
@ -1410,10 +1410,17 @@ util.inspect(process);
|
|||||||
// Test that a long linked list can be inspected without throwing an error.
|
// Test that a long linked list can be inspected without throwing an error.
|
||||||
const list = {};
|
const list = {};
|
||||||
let head = list;
|
let head = list;
|
||||||
// The real cutoff value is closer to 1400 stack frames as of May 2018,
|
// A linked list of length 100k should be inspectable in some way, even though
|
||||||
// but let's be generous here – even a linked listed of length 100k should be
|
// the real cutoff value is much lower than 100k.
|
||||||
// inspectable in some way.
|
|
||||||
for (let i = 0; i < 100000; i++)
|
for (let i = 0; i < 100000; i++)
|
||||||
head = head.next = {};
|
head = head.next = {};
|
||||||
util.inspect(list);
|
assert.strictEqual(
|
||||||
|
util.inspect(list),
|
||||||
|
'{ next: { next: { next: [Object] } } }'
|
||||||
|
);
|
||||||
|
const longList = util.inspect(list, { depth: Infinity });
|
||||||
|
const match = longList.match(/next/g);
|
||||||
|
assert(match.length > 1000 && match.length < 10000);
|
||||||
|
assert(longList.includes('[Object: Inspection interrupted ' +
|
||||||
|
'prematurely. Maximum call stack size exceeded.]'));
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user