Skip to content

Commit

Permalink
util: do not rely on mutable Object and Function' constructor prop
Browse files Browse the repository at this point in the history
PR-URL: #56188
Fixes: #55924
Reviewed-By: Ruben Bridgewater <[email protected]>
Reviewed-By: Jordan Harband <[email protected]>
  • Loading branch information
aduh95 authored and ruyadorno committed Dec 20, 2024
1 parent 16b1ad8 commit c365263
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 5 deletions.
30 changes: 25 additions & 5 deletions lib/internal/util/inspect.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@ const {
DatePrototypeToISOString,
DatePrototypeToString,
ErrorPrototypeToString,
Function,
FunctionPrototype,
FunctionPrototypeBind,
FunctionPrototypeCall,
FunctionPrototypeSymbolHasInstance,
FunctionPrototypeToString,
JSONStringify,
MapPrototypeEntries,
Expand All @@ -50,6 +53,7 @@ const {
ObjectGetPrototypeOf,
ObjectIs,
ObjectKeys,
ObjectPrototype,
ObjectPrototypeHasOwnProperty,
ObjectPrototypePropertyIsEnumerable,
ObjectSeal,
Expand Down Expand Up @@ -593,10 +597,26 @@ function isInstanceof(object, proto) {
}
}

// Special-case for some builtin prototypes in case their `constructor` property has been tampered.
const wellKnownPrototypes = new SafeMap();
wellKnownPrototypes.set(ObjectPrototype, { name: 'Object', constructor: Object });
wellKnownPrototypes.set(FunctionPrototype, { name: 'Function', constructor: Function });

function getConstructorName(obj, ctx, recurseTimes, protoProps) {
let firstProto;
const tmp = obj;
while (obj || isUndetectableObject(obj)) {
const wellKnownPrototypeNameAndConstructor = wellKnownPrototypes.get(obj);
if (wellKnownPrototypeNameAndConstructor != null) {
const { name, constructor } = wellKnownPrototypeNameAndConstructor;
if (FunctionPrototypeSymbolHasInstance(constructor, tmp)) {
if (protoProps !== undefined && firstProto !== obj) {
addPrototypeProperties(
ctx, tmp, firstProto || tmp, recurseTimes, protoProps);
}
return name;
}
}
const descriptor = ObjectGetOwnPropertyDescriptor(obj, 'constructor');
if (descriptor !== undefined &&
typeof descriptor.value === 'function' &&
Expand Down Expand Up @@ -954,7 +974,11 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
if (noIterator) {
keys = getKeys(value, ctx.showHidden);
braces = ['{', '}'];
if (constructor === 'Object') {
if (typeof value === 'function') {
base = getFunctionBase(value, constructor, tag);
if (keys.length === 0 && protoProps === undefined)
return ctx.stylize(base, 'special');
} else if (constructor === 'Object') {
if (isArgumentsObject(value)) {
braces[0] = '[Arguments] {';
} else if (tag !== '') {
Expand All @@ -963,10 +987,6 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
if (keys.length === 0 && protoProps === undefined) {
return `${braces[0]}}`;
}
} else if (typeof value === 'function') {
base = getFunctionBase(value, constructor, tag);
if (keys.length === 0 && protoProps === undefined)
return ctx.stylize(base, 'special');
} else if (isRegExp(value)) {
// Make RegExps say that they are RegExps
base = RegExpPrototypeToString(
Expand Down
30 changes: 30 additions & 0 deletions test/parallel/test-util-inspect.js
Original file line number Diff line number Diff line change
Expand Up @@ -3323,3 +3323,33 @@ assert.strictEqual(
}
}), '{ [Symbol(Symbol.iterator)]: [Getter] }');
}

{
const o = {};
const { prototype: BuiltinPrototype } = Object;
const desc = Reflect.getOwnPropertyDescriptor(BuiltinPrototype, 'constructor');
Object.defineProperty(BuiltinPrototype, 'constructor', {
get: () => BuiltinPrototype,
configurable: true,
});
assert.strictEqual(
util.inspect(o),
'{}',
);
Object.defineProperty(BuiltinPrototype, 'constructor', desc);
}

{
const o = { f() {} };
const { prototype: BuiltinPrototype } = Function;
const desc = Reflect.getOwnPropertyDescriptor(BuiltinPrototype, 'constructor');
Object.defineProperty(BuiltinPrototype, 'constructor', {
get: () => BuiltinPrototype,
configurable: true,
});
assert.strictEqual(
util.inspect(o),
'{ f: [Function: f] }',
);
Object.defineProperty(BuiltinPrototype, 'constructor', desc);
}

0 comments on commit c365263

Please sign in to comment.