Skip to content

Commit 9120924

Browse files
authored
util: fix nested proxy inspection
Fixes: #61061 PR-URL: #61077 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: LiviaMedeiros <livia@cirno.name> Reviewed-By: Juan José Arboleda <soyjuanarbol@gmail.com> Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
1 parent 799feac commit 9120924

2 files changed

Lines changed: 59 additions & 16 deletions

File tree

‎lib/internal/util/inspect.js‎

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,17 +1118,29 @@ function formatValue(ctx, value, recurseTimes, typedArray) {
11181118

11191119
// Memorize the context for custom inspection on proxies.
11201120
constcontext=value;
1121+
letproxies=0;
11211122
// Always check for proxies to prevent side effects and to prevent triggering
11221123
// any proxy handlers.
1123-
constproxy=getProxyDetails(value,!!ctx.showProxy);
1124+
letproxy=getProxyDetails(value,!!ctx.showProxy);
11241125
if(proxy!==undefined){
1125-
if(proxy===null||proxy[0]===null){
1126-
returnctx.stylize('<Revoked Proxy>','special');
1127-
}
11281126
if(ctx.showProxy){
1127+
if(proxy[0]===null){
1128+
returnctx.stylize('<Revoked Proxy>','special');
1129+
}
11291130
returnformatProxy(ctx,proxy,recurseTimes);
11301131
}
1131-
value=proxy;
1132+
do{
1133+
if(proxy===null){
1134+
letformatted=ctx.stylize('<Revoked Proxy>','special');
1135+
for(leti=0;i<proxies;i++){
1136+
formatted=`${ctx.stylize('Proxy(','special')}${formatted}${ctx.stylize(')','special')}`;
1137+
}
1138+
returnformatted;
1139+
}
1140+
value=proxy;
1141+
proxy=getProxyDetails(value,false);
1142+
proxies+=1;
1143+
}while(proxy!==undefined);
11321144
}
11331145

11341146
// Provide a hook for user-specified inspect functions.
@@ -1144,7 +1156,7 @@ function formatValue(ctx, value, recurseTimes, typedArray) {
11441156
// a counter internally.
11451157
constdepth=ctx.depth===null ? null : ctx.depth-recurseTimes;
11461158
constisCrossContext=
1147-
proxy!==undefined||!FunctionPrototypeSymbolHasInstance(Object,context);
1159+
proxies!==0||!FunctionPrototypeSymbolHasInstance(Object,context);
11481160
constret=FunctionPrototypeCall(
11491161
maybeCustom,
11501162
context,
@@ -1180,10 +1192,12 @@ function formatValue(ctx, value, recurseTimes, typedArray) {
11801192
returnctx.stylize(`[Circular *${index}]`,'special');
11811193
}
11821194

1183-
constformatted=formatRaw(ctx,value,recurseTimes,typedArray);
1195+
letformatted=formatRaw(ctx,value,recurseTimes,typedArray);
11841196

1185-
if(proxy!==undefined){
1186-
return`${ctx.stylize('Proxy(','special')}${formatted}${ctx.stylize(')','special')}`;
1197+
if(proxies!==0){
1198+
for(leti=0;i<proxies;i++){
1199+
formatted=`${ctx.stylize('Proxy(','special')}${formatted}${ctx.stylize(')','special')}`;
1200+
}
11871201
}
11881202

11891203
returnformatted;
@@ -2691,7 +2705,7 @@ function hasBuiltInToString(value) {
26912705
if(proxyTarget===null){
26922706
returntrue;
26932707
}
2694-
value=proxyTarget;
2708+
returnhasBuiltInToString(proxyTarget);
26952709
}
26962710

26972711
lethasOwnToString=ObjectPrototypeHasOwnProperty;

‎test/parallel/test-util-inspect-proxy.js‎

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,11 @@ proxyObj = new Proxy(target, handler);
4242
util.inspect(proxyObj,opts);
4343

4444
// Make sure inspecting object does not trigger any proxy traps.
45-
util.format('%s',proxyObj);
45+
// %i%f%d use Symbol.toPrimitive to convert the value to a string.
46+
// %j uses JSON.stringify, accessing the value's toJSON and toString method.
47+
util.format('%s%o%O%c',proxyObj,proxyObj,proxyObj,proxyObj);
48+
constnestedProxy=newProxy(newProxy({},handler),{});
49+
util.format('%s%o%O%c',nestedProxy,nestedProxy,nestedProxy,nestedProxy);
4650

4751
// getProxyDetails is an internal method, not intended for public use.
4852
// This is here to test that the internals are working correctly.
@@ -135,6 +139,10 @@ const expected6 = 'Proxy [\n' +
135139
' Proxy [ Proxy [Array], Proxy [Array] ]\n'+
136140
' ]\n'+
137141
']';
142+
constexpected2NoShowProxy='Proxy(Proxy({}))';
143+
constexpected3NoShowProxy='Proxy(Proxy(Proxy({})))';
144+
constexpected4NoShowProxy='Proxy(Proxy(Proxy(Proxy({}))))';
145+
constexpected5NoShowProxy='Proxy(Proxy(Proxy(Proxy(Proxy({})))))';
138146
assert.strictEqual(
139147
util.inspect(proxy1,{showProxy: 1,depth: null}),
140148
expected1);
@@ -144,11 +152,11 @@ assert.strictEqual(util.inspect(proxy4, opts), expected4);
144152
assert.strictEqual(util.inspect(proxy5,opts),expected5);
145153
assert.strictEqual(util.inspect(proxy6,opts),expected6);
146154
assert.strictEqual(util.inspect(proxy1),expected0);
147-
assert.strictEqual(util.inspect(proxy2),expected0);
148-
assert.strictEqual(util.inspect(proxy3),expected0);
149-
assert.strictEqual(util.inspect(proxy4),expected0);
150-
assert.strictEqual(util.inspect(proxy5),expected0);
151-
assert.strictEqual(util.inspect(proxy6),expected0);
155+
assert.strictEqual(util.inspect(proxy2),expected2NoShowProxy);
156+
assert.strictEqual(util.inspect(proxy3),expected3NoShowProxy);
157+
assert.strictEqual(util.inspect(proxy4),expected2NoShowProxy);
158+
assert.strictEqual(util.inspect(proxy5),expected4NoShowProxy);
159+
assert.strictEqual(util.inspect(proxy6),expected5NoShowProxy);
152160

153161
// Just for fun, let's create a Proxy using Arrays.
154162
constproxy7=newProxy([],[]);
@@ -188,3 +196,24 @@ assert.strictEqual(
188196
')\x1B[39m'
189197
);
190198
assert.strictEqual(util.format('%s',proxy12),'Proxy([ 1, 2, 3 ])');
199+
200+
{
201+
// Nested proxies should not trigger any proxy handlers.
202+
constnestedProxy=newProxy(newProxy(newProxy({},handler),{}),{});
203+
204+
assert.strictEqual(
205+
util.inspect(nestedProxy,{showProxy: true}),
206+
'Proxy [ Proxy [ Proxy [ {}, [Object] ], {} ], {} ]'
207+
);
208+
assert.strictEqual(util.inspect(nestedProxy,{showProxy: false}),expected3NoShowProxy);
209+
}
210+
211+
{
212+
// Nested revoked proxies should work as expected as well as custom inspection functions.
213+
constrevocable=Proxy.revocable({},handler);
214+
revocable.revoke();
215+
constnestedProxy=newProxy(revocable.proxy,{});
216+
217+
assert.strictEqual(util.inspect(nestedProxy,{showProxy: true}),'Proxy [ <Revoked Proxy>, {} ]');
218+
assert.strictEqual(util.inspect(nestedProxy,{showProxy: false}),'Proxy(<Revoked Proxy>)');
219+
}

0 commit comments

Comments
 (0)