Skip to content

Commit 77397c5

Browse files
aduh95targos
authored andcommitted
util: do not rely on mutable Object and Function' constructor prop
PR-URL: #56188 Fixes: #55924 Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Jordan Harband <ljharb@gmail.com>
1 parent f3b3ff8 commit 77397c5

File tree

2 files changed

+55
-5
lines changed

2 files changed

+55
-5
lines changed

lib/internal/util/inspect.js

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,11 @@ const {
2222
DatePrototypeToISOString,
2323
DatePrototypeToString,
2424
ErrorPrototypeToString,
25+
Function,
26+
FunctionPrototype,
2527
FunctionPrototypeBind,
2628
FunctionPrototypeCall,
29+
FunctionPrototypeSymbolHasInstance,
2730
FunctionPrototypeToString,
2831
JSONStringify,
2932
MapPrototypeEntries,
@@ -50,6 +53,7 @@ const {
5053
ObjectGetPrototypeOf,
5154
ObjectIs,
5255
ObjectKeys,
56+
ObjectPrototype,
5357
ObjectPrototypeHasOwnProperty,
5458
ObjectPrototypePropertyIsEnumerable,
5559
ObjectSeal,
@@ -593,10 +597,26 @@ function isInstanceof(object, proto) {
593597
}
594598
}
595599

600+
// Special-case for some builtin prototypes in case their `constructor` property has been tampered.
601+
const wellKnownPrototypes = new SafeMap();
602+
wellKnownPrototypes.set(ObjectPrototype, { name: 'Object', constructor: Object });
603+
wellKnownPrototypes.set(FunctionPrototype, { name: 'Function', constructor: Function });
604+
596605
function getConstructorName(obj, ctx, recurseTimes, protoProps) {
597606
let firstProto;
598607
const tmp = obj;
599608
while (obj || isUndetectableObject(obj)) {
609+
const wellKnownPrototypeNameAndConstructor = wellKnownPrototypes.get(obj);
610+
if (wellKnownPrototypeNameAndConstructor != null) {
611+
const { name, constructor } = wellKnownPrototypeNameAndConstructor;
612+
if (FunctionPrototypeSymbolHasInstance(constructor, tmp)) {
613+
if (protoProps !== undefined && firstProto !== obj) {
614+
addPrototypeProperties(
615+
ctx, tmp, firstProto || tmp, recurseTimes, protoProps);
616+
}
617+
return name;
618+
}
619+
}
600620
const descriptor = ObjectGetOwnPropertyDescriptor(obj, 'constructor');
601621
if (descriptor !== undefined &&
602622
typeof descriptor.value === 'function' &&
@@ -954,7 +974,11 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
954974
if (noIterator) {
955975
keys = getKeys(value, ctx.showHidden);
956976
braces = ['{', '}'];
957-
if (constructor === 'Object') {
977+
if (typeof value === 'function') {
978+
base = getFunctionBase(value, constructor, tag);
979+
if (keys.length === 0 && protoProps === undefined)
980+
return ctx.stylize(base, 'special');
981+
} else if (constructor === 'Object') {
958982
if (isArgumentsObject(value)) {
959983
braces[0] = '[Arguments] {';
960984
} else if (tag !== '') {
@@ -963,10 +987,6 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
963987
if (keys.length === 0 && protoProps === undefined) {
964988
return `${braces[0]}}`;
965989
}
966-
} else if (typeof value === 'function') {
967-
base = getFunctionBase(value, constructor, tag);
968-
if (keys.length === 0 && protoProps === undefined)
969-
return ctx.stylize(base, 'special');
970990
} else if (isRegExp(value)) {
971991
// Make RegExps say that they are RegExps
972992
base = RegExpPrototypeToString(

test/parallel/test-util-inspect.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3323,3 +3323,33 @@ assert.strictEqual(
33233323
}
33243324
}), '{ [Symbol(Symbol.iterator)]: [Getter] }');
33253325
}
3326+
3327+
{
3328+
const o = {};
3329+
const { prototype: BuiltinPrototype } = Object;
3330+
const desc = Reflect.getOwnPropertyDescriptor(BuiltinPrototype, 'constructor');
3331+
Object.defineProperty(BuiltinPrototype, 'constructor', {
3332+
get: () => BuiltinPrototype,
3333+
configurable: true,
3334+
});
3335+
assert.strictEqual(
3336+
util.inspect(o),
3337+
'{}',
3338+
);
3339+
Object.defineProperty(BuiltinPrototype, 'constructor', desc);
3340+
}
3341+
3342+
{
3343+
const o = { f() {} };
3344+
const { prototype: BuiltinPrototype } = Function;
3345+
const desc = Reflect.getOwnPropertyDescriptor(BuiltinPrototype, 'constructor');
3346+
Object.defineProperty(BuiltinPrototype, 'constructor', {
3347+
get: () => BuiltinPrototype,
3348+
configurable: true,
3349+
});
3350+
assert.strictEqual(
3351+
util.inspect(o),
3352+
'{ f: [Function: f] }',
3353+
);
3354+
Object.defineProperty(BuiltinPrototype, 'constructor', desc);
3355+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy