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: #37079Fixes: #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‎

Lines changed: 3 additions & 0 deletions
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(constkeyofkeys){
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‎

Lines changed: 52 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,61 @@ require('../common');
77

88
constassert=require('assert');
99

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

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

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

22-
constresult=util.inspect(newX(),{
23-
getters: true,
24-
showHidden: true
25-
});
34+
// Regression test for https://github.com/nodejs/node/issues/37054
35+
{
36+
classA{
37+
constructor(B){
38+
this.B=B;
39+
}
40+
getb(){
41+
returnthis.B;
42+
}
43+
}
44+
45+
classB{
46+
constructor(){
47+
this.A=newA(this);
48+
}
49+
geta(){
50+
returnthis.A;
51+
}
52+
}
53+
54+
constresult=inspect(newB(),{
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)