Bug 1406085 - Only consider array indices to be indexed properties. r=nchevobbe

MozReview-Commit-ID: AEH4BeFunxh

--HG--
extra : rebase_source : e61ca2d40e5026bb8e4caaeedacb5278353788c8
This commit is contained in:
Oriol Brufau 2017-10-05 17:03:07 +02:00
parent 28bfd5dbba
commit c06b45beac
2 changed files with 23 additions and 17 deletions

View File

@ -871,13 +871,13 @@ PropertyIteratorActor.prototype.requestTypes = {
function enumArrayProperties(objectActor, options) {
let length = DevToolsUtils.getProperty(objectActor.obj, "length");
if (!isSafePositiveInteger(length)) {
if (!isUint32(length)) {
// Pseudo arrays are flagged as ArrayLike if they have
// subsequent indexed properties without having any length attribute.
length = 0;
let names = objectActor.obj.getOwnPropertyNames();
for (let key of names) {
if (!isSafeIndex(key) || key != length++) {
if (!isArrayIndex(key) || key != length++) {
break;
}
}
@ -908,22 +908,22 @@ function enumObjectProperties(objectActor, options) {
let sliceIndex;
const isLengthTrustworthy =
isSafePositiveInteger(length)
&& (length > 0 && isSafeIndex(names[length - 1]))
&& !isSafeIndex(names[length]);
isUint32(length)
&& (!length || isArrayIndex(names[length - 1]))
&& !isArrayIndex(names[length]);
if (!isLengthTrustworthy) {
// The length property may not reflect what the object looks like, let's find
// where indexed properties end.
if (!isSafeIndex(names[0])) {
if (!isArrayIndex(names[0])) {
// If the first item is not a number, this means there is no indexed properties
// in this object.
sliceIndex = 0;
} else {
sliceIndex = names.length;
while (sliceIndex > 0) {
if (isSafeIndex(names[sliceIndex - 1])) {
if (isArrayIndex(names[sliceIndex - 1])) {
break;
}
sliceIndex--;
@ -2532,28 +2532,30 @@ function isArray(object) {
}
/**
* Returns true if the parameter is a safe positive integer.
* Returns true if the parameter can be stored as a 32-bit unsigned integer.
* If so, it will be suitable for use as the length of an array object.
*
* @param num Number
* The number to test.
* @return Boolean
*/
function isSafePositiveInteger(num) {
return Number.isSafeInteger(num) && 1 / num > 0;
function isUint32(num) {
return num >>> 0 === num;
}
/**
* Returns true if the parameter is suitable to be an array index.
*
* @param num Any
* @param str String
* @return Boolean
*/
function isSafeIndex(str) {
// Transform the parameter to a number using the Unary operator.
let num = +str;
return isSafePositiveInteger(num) &&
// Check the string since unary can transform non number (boolean, null, …).
num + "" === str;
function isArrayIndex(str) {
// Transform the parameter to a 32-bit unsigned integer.
let num = str >>> 0;
// Check that the parameter is a canonical Uint32 index.
return num + "" === str &&
// Array indices cannot attain the maximum Uint32 value.
num != -1 >>> 0;
}
exports.ObjectActor = ObjectActor;

View File

@ -92,6 +92,10 @@ async function run_test_with_server(server) {
evaledObject: { 1: 1 },
expectedIndexedProperties: [["1", 1]],
expectedNonIndexedProperties: [],
}, {
evaledObject: { a: 1, [2 ** 32 - 2]: 2, [2 ** 32 - 1]: 3 },
expectedIndexedProperties: [["4294967294", 2]],
expectedNonIndexedProperties: [["a", 1], ["4294967295", 3]],
}, {
evaledObject: `(() => {
x = [12, 42];