GeezerVison is showing github.com — util: do not rely on mutable `Object` and `Function`' `constructor` prop · nodejs/node@9e98e86
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: lib/internal/util/inspect.js +25-5Lines changed: 25 additions & 5 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -22,8 +22,11 @@ const { | 22 | 22 | DatePrototypeToISOString, | 23 | 23 | DatePrototypeToString, | 24 | 24 | ErrorPrototypeToString, | | 25 | + Function, | | 26 | + FunctionPrototype, | 25 | 27 | FunctionPrototypeBind, | 26 | 28 | FunctionPrototypeCall, | | 29 | + FunctionPrototypeSymbolHasInstance, | 27 | 30 | FunctionPrototypeToString, | 28 | 31 | JSONStringify, | 29 | 32 | MapPrototypeEntries, | @@ -50,6 +53,7 @@ const { | 50 | 53 | ObjectGetPrototypeOf, | 51 | 54 | ObjectIs, | 52 | 55 | ObjectKeys, | | 56 | + ObjectPrototype, | 53 | 57 | ObjectPrototypeHasOwnProperty, | 54 | 58 | ObjectPrototypePropertyIsEnumerable, | 55 | 59 | ObjectSeal, | @@ -593,10 +597,26 @@ function isInstanceof(object, proto) { | 593 | 597 | } | 594 | 598 | } | 595 | 599 |
| | 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 | + | 596 | 605 | function getConstructorName(obj, ctx, recurseTimes, protoProps) { | 597 | 606 | let firstProto; | 598 | 607 | const tmp = obj; | 599 | 608 | 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 | + } | 600 | 620 | const descriptor = ObjectGetOwnPropertyDescriptor(obj, 'constructor'); | 601 | 621 | if (descriptor !== undefined && | 602 | 622 | typeof descriptor.value === 'function' && | @@ -954,7 +974,11 @@ function formatRaw(ctx, value, recurseTimes, typedArray) { | 954 | 974 | if (noIterator) { | 955 | 975 | keys = getKeys(value, ctx.showHidden); | 956 | 976 | 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') { | 958 | 982 | if (isArgumentsObject(value)) { | 959 | 983 | braces[0] = '[Arguments] {'; | 960 | 984 | } else if (tag !== '') { | @@ -963,10 +987,6 @@ function formatRaw(ctx, value, recurseTimes, typedArray) { | 963 | 987 | if (keys.length === 0 && protoProps === undefined) { | 964 | 988 | return `${braces[0]}}`; | 965 | 989 | } | 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'); | 970 | 990 | } else if (isRegExp(value)) { | 971 | 991 | // Make RegExps say that they are RegExps | 972 | 992 | base = RegExpPrototypeToString( | |
Collapse file Copy file name to clipboardExpand all lines: test/parallel/test-util-inspect.js +30Lines changed: 30 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -3323,3 +3323,33 @@ assert.strictEqual( | 3323 | 3323 | } | 3324 | 3324 | }), '{ [Symbol(Symbol.iterator)]: [Getter] }'); | 3325 | 3325 | } | | 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 | +} |
|