From e00c69c37e96d836fa1ce340b5219b4dfd44e6fa Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Sat, 12 Jan 2019 00:15:10 +0100 Subject: [PATCH] util: fix iterable types with special prototype The fallback should only be taken for a null prototype. If an iterable data type (e.g., Array) has a prototype without `Symbol.iterator`, just try the best to visualize it as object. Fixes: https://github.com/nodejs/node/issues/25451 --- lib/internal/util/inspect.js | 28 ++++++++++++---------------- test/parallel/test-util-inspect.js | 10 ++++++++++ 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/lib/internal/util/inspect.js b/lib/internal/util/inspect.js index 88362f8615f844..0f81ab5d0296e9 100644 --- a/lib/internal/util/inspect.js +++ b/lib/internal/util/inspect.js @@ -463,28 +463,22 @@ function clazzWithNullPrototype(clazz, name) { function noPrototypeIterator(ctx, value, recurseTimes) { let newVal; if (isSet(value)) { - const clazz = Object.getPrototypeOf(value) || - clazzWithNullPrototype(Set, 'Set'); + const clazz = clazzWithNullPrototype(Set, 'Set'); newVal = new clazz(setValues(value)); } else if (isMap(value)) { - const clazz = Object.getPrototypeOf(value) || - clazzWithNullPrototype(Map, 'Map'); + const clazz = clazzWithNullPrototype(Map, 'Map'); newVal = new clazz(mapEntries(value)); } else if (Array.isArray(value)) { - const clazz = Object.getPrototypeOf(value) || - clazzWithNullPrototype(Array, 'Array'); + const clazz = clazzWithNullPrototype(Array, 'Array'); newVal = new clazz(value.length); } else if (isTypedArray(value)) { - let clazz = Object.getPrototypeOf(value); - if (!clazz) { - const constructor = findTypedConstructor(value); - clazz = clazzWithNullPrototype(constructor, constructor.name); - } + const constructor = findTypedConstructor(value); + const clazz = clazzWithNullPrototype(constructor, constructor.name); newVal = new clazz(value); } - if (newVal) { + if (newVal !== undefined) { Object.defineProperties(newVal, Object.getOwnPropertyDescriptors(value)); - return formatValue(ctx, newVal, recurseTimes); + return formatRaw(ctx, newVal, recurseTimes); } } @@ -728,9 +722,11 @@ function formatRaw(ctx, value, recurseTimes, typedArray) { } else { // The input prototype got manipulated. Special handle these. We have to // rebuild the information so we are able to display everything. - const specialIterator = noPrototypeIterator(ctx, value, recurseTimes); - if (specialIterator) { - return specialIterator; + if (constructor === null) { + const specialIterator = noPrototypeIterator(ctx, value, recurseTimes); + if (specialIterator) { + return specialIterator; + } } if (isMapIterator(value)) { braces = [`[${tag || 'Map Iterator'}] {`, '}']; diff --git a/test/parallel/test-util-inspect.js b/test/parallel/test-util-inspect.js index c9ca8f5787735a..76f8caa31a88b8 100644 --- a/test/parallel/test-util-inspect.js +++ b/test/parallel/test-util-inspect.js @@ -1853,6 +1853,16 @@ assert.strictEqual( util.inspect(new StorageObject()), '<[Object: null prototype] {}> {}' ); + + obj = [1, 2, 3]; + Object.setPrototypeOf(obj, Number.prototype); + assert.strictEqual(inspect(obj), "Number { '0': 1, '1': 2, '2': 3 }"); + + Object.setPrototypeOf(obj, Object.create(null)); + assert.strictEqual( + inspect(obj), + "<[Object: null prototype] {}> { '0': 1, '1': 2, '2': 3 }" + ); } // Check that the fallback always works.