Skip to content

Commit ec5b06e

Browse files
BridgeARtargos
authored andcommitted
util: fix infinite recursion during inspection
A specially crafted object with circular structures behind getters could cause a infinite recursion. This is now fixed by detecting the objects as already visited. Signed-off-by: Ruben Bridgewater <[email protected]> PR-URL: #37079 Fixes: #37054 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Rich Trott <[email protected]> Reviewed-By: Juan José Arboleda <[email protected]> Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Anto Aravinth <[email protected]> Reviewed-By: Trivikram Kamat <[email protected]>
1 parent 67e9e71 commit ec5b06e

File tree

2 files changed

+55
-15
lines changed

2 files changed

+55
-15
lines changed

lib/internal/util/inspect.js

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const {
55
ArrayIsArray,
66
ArrayPrototypeFilter,
77
ArrayPrototypeForEach,
8+
ArrayPrototypePop,
89
ArrayPrototypePush,
910
ArrayPrototypePushApply,
1011
ArrayPrototypeSort,
@@ -620,6 +621,7 @@ function addPrototypeProperties(ctx, main, obj, recurseTimes, output) {
620621
}
621622
// Get all own property names and symbols.
622623
keys = ReflectOwnKeys(obj);
624+
ArrayPrototypePush(ctx.seen, main);
623625
for (const key of keys) {
624626
// Ignore the `constructor` property and keys that exist on layers above.
625627
if (key === 'constructor' ||
@@ -640,6 +642,7 @@ function addPrototypeProperties(ctx, main, obj, recurseTimes, output) {
640642
ArrayPrototypePush(output, value);
641643
}
642644
}
645+
ArrayPrototypePop(ctx.seen);
643646
// Limit the inspection to up to three prototype layers. Using `recurseTimes`
644647
// is not a good choice here, because it's as if the properties are declared
645648
// on the current object from the users perspective.

test/parallel/test-util-inspect-getters-accessing-this.js

+52-15
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,61 @@ require('../common');
77

88
const assert = require('assert');
99

10-
const util = require('util');
10+
const { inspect } = require('util');
1111

12-
class X {
13-
constructor() {
14-
this._y = 123;
15-
}
12+
{
13+
class X {
14+
constructor() {
15+
this._y = 123;
16+
}
1617

17-
get y() {
18-
return this._y;
18+
get y() {
19+
return this._y;
20+
}
1921
}
22+
23+
const result = inspect(new X(), {
24+
getters: true,
25+
showHidden: true
26+
});
27+
28+
assert.strictEqual(
29+
result,
30+
'X { _y: 123, [y]: [Getter: 123] }'
31+
);
2032
}
2133

22-
const result = util.inspect(new X(), {
23-
getters: true,
24-
showHidden: true
25-
});
34+
// Regression test for https://github.com/nodejs/node/issues/37054
35+
{
36+
class A {
37+
constructor(B) {
38+
this.B = B;
39+
}
40+
get b() {
41+
return this.B;
42+
}
43+
}
44+
45+
class B {
46+
constructor() {
47+
this.A = new A(this);
48+
}
49+
get a() {
50+
return this.A;
51+
}
52+
}
53+
54+
const result = inspect(new B(), {
55+
depth: 1,
56+
getters: true,
57+
showHidden: true
58+
});
2659

27-
assert.strictEqual(
28-
result,
29-
'X { _y: 123, [y]: [Getter: 123] }'
30-
);
60+
assert.strictEqual(
61+
result,
62+
'<ref *1> B {\n' +
63+
' A: A { B: [Circular *1], [b]: [Getter] [Circular *1] },\n' +
64+
' [a]: [Getter] A { B: [Circular *1], [b]: [Getter] [Circular *1] }\n' +
65+
'}',
66+
);
67+
}

0 commit comments

Comments
 (0)