1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-23 20:55:08 +00:00

LibJS: Don't treat 2^32 - 1 as numeric PropertyName

10.4.2 Array Exotic Objects
    https://tc39.es/ecma262/#sec-array-exotic-objects

    A String property name P is an array index if and only if
    ToString(ToUint32(P)) equals P and ToUint32(P) is not the same value
    as 𝔽(2^32 - 1).
This commit is contained in:
Linus Groh 2021-07-06 16:45:54 +01:00
parent 47bd25a2f1
commit 83f61748a5
2 changed files with 34 additions and 4 deletions

View file

@ -31,7 +31,7 @@ public:
return {}; return {};
if (value.is_symbol()) if (value.is_symbol())
return value.as_symbol(); return value.as_symbol();
if (value.is_integral_number() && value.as_double() >= 0 && value.as_double() <= NumericLimits<u32>::max()) if (value.is_integral_number() && value.as_double() >= 0 && value.as_double() < NumericLimits<u32>::max())
return value.as_u32(); return value.as_u32();
auto string = value.to_string(global_object); auto string = value.to_string(global_object);
if (string.is_null()) if (string.is_null())
@ -49,8 +49,8 @@ public:
// FIXME: Replace this with requires(IsUnsigned<T>)? // FIXME: Replace this with requires(IsUnsigned<T>)?
// Needs changes in various places using `int` (but not actually being in the negative range) // Needs changes in various places using `int` (but not actually being in the negative range)
VERIFY(index >= 0); VERIFY(index >= 0);
if constexpr (NumericLimits<T>::max() > NumericLimits<u32>::max()) if constexpr (NumericLimits<T>::max() >= NumericLimits<u32>::max())
VERIFY(index <= NumericLimits<u32>::max()); VERIFY(index < NumericLimits<u32>::max());
} }
PropertyName(char const* chars) PropertyName(char const* chars)
@ -131,7 +131,7 @@ public:
} }
auto property_index = m_string.to_uint(TrimWhitespace::No); auto property_index = m_string.to_uint(TrimWhitespace::No);
if (!property_index.has_value()) { if (!property_index.has_value() || property_index.value() == NumericLimits<u32>::max()) {
m_string_may_be_number = false; m_string_may_be_number = false;
return false; return false;
} }

View file

@ -0,0 +1,30 @@
test("numeric properties", () => {
const i32Max = 2 ** 31 - 1;
const u32Max = 2 ** 32 - 1;
const o = {
[-1]: "foo",
0: "foo",
1: "foo",
[i32Max - 1]: "foo",
[i32Max]: "foo",
[i32Max + 1]: "foo",
[u32Max - 1]: "foo",
[u32Max]: "foo",
[u32Max + 1]: "foo",
};
// Numeric properties come first in Object.getOwnPropertyNames()'s output,
// which means we can test what each is treated as internally.
expect(Object.getOwnPropertyNames(o)).toEqual([
// Numeric properties
"0",
"1",
"2147483646",
"2147483647",
"2147483648",
"4294967294",
// Non-numeric properties
"-1",
"4294967295", // >= 2^32 - 1
"4294967296", // >= 2^32 - 1
]);
});