diff --git a/lib/util.js b/lib/util.js index b3c9dd8cf140e9..cbd8f0cfcd156d 100644 --- a/lib/util.js +++ b/lib/util.js @@ -652,6 +652,9 @@ function formatSpecialArray(ctx, value, recurseTimes, keys, maxLength, valLen) { if (visibleLength === maxLength) break; const index = +key; + // Arrays can only have up to 2^32 - 1 entries + if (index > 2 ** 32 - 2) + break; if (i !== index) { if (!numberRegExp.test(key)) break; @@ -674,6 +677,8 @@ function formatSpecialArray(ctx, value, recurseTimes, keys, maxLength, valLen) { const message = `<${len} empty item${ending}>`; output.push(ctx.stylize(message, 'undefined')); i = valLen; + if (keyLen === 0) + return output; } const remaining = valLen - i; if (remaining > 0) { @@ -687,13 +692,18 @@ function formatSpecialArray(ctx, value, recurseTimes, keys, maxLength, valLen) { // The array is not sparse for (i = valLen; i < keyLen; i++) output.push(formatProperty(ctx, value, recurseTimes, keys[i], 2)); - } else if (keyLen !== 0 && keys[keyLen - 1] !== `${valLen - 1}`) { - for (const key of keys) { - // Skip regular indices - if (!numberRegExp.test(key)) { - output.push(formatProperty(ctx, value, recurseTimes, key, 2)); - } + } else if (keys[keyLen - 1] !== `${valLen - 1}`) { + const extra = []; + // Only handle special keys + var key; + for (i = keys.length - 1; i >= 0; i--) { + key = keys[i]; + if (numberRegExp.test(key) && +key < 2 ** 32 - 1) + break; + extra.push(formatProperty(ctx, value, recurseTimes, key, 2)); } + for (i = extra.length - 1; i >= 0; i--) + output.push(extra[i]); } return output; } diff --git a/test/parallel/test-util-inspect.js b/test/parallel/test-util-inspect.js index 6f0a7f3e115a62..13777c0388c212 100644 --- a/test/parallel/test-util-inspect.js +++ b/test/parallel/test-util-inspect.js @@ -361,6 +361,29 @@ assert.strictEqual( assert.strictEqual(util.inspect(arr3), "[ '-1': -1 ]"); } +// Indices out of bounds +{ + const arr = []; + arr[2 ** 32] = true; // not a valid array index + assert.strictEqual(util.inspect(arr), "[ '4294967296': true ]"); + arr[0] = true; + arr[10] = true; + assert.strictEqual(util.inspect(arr), + "[ true, <9 empty items>, true, '4294967296': true ]"); + arr[2 ** 32 - 2] = true; + arr[2 ** 32 - 1] = true; + arr[2 ** 32 + 1] = true; + delete arr[0]; + delete arr[10]; + assert.strictEqual(util.inspect(arr), + ['[ <4294967294 empty items>,', + 'true,', + "'4294967296': true,", + "'4294967295': true,", + "'4294967297': true ]" + ].join('\n ')); +} + // Function with properties { const value = () => {};