mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-05-11 13:42:52 +00:00
LibJS: Fix two issues with array (length > INT32_MAX)
1. Allow Value(size_t) and use it for array length properties. If an array length can't fit in an Int32 value, we shouldn't go out of or way to force it into one. Instead, for values above INT32_MAX, we simply store them as Double values. 2. Switch to generic indexed property storage for large arrays. Previously we would always allocate array storage eagerly when the length property was set. This meant that "a.length = 0x80000000" would trivially DOS the engine on 32-bit since we don't have that much VM. We now switch to generic storage when changing the length moves us over the 4M entry mark. Fixes #5986.
This commit is contained in:
parent
54f6b52f71
commit
077406dc36
Notes:
sideshowbarker
2024-07-18 20:57:20 +09:00
Author: https://github.com/awesomekling
Commit: 077406dc36
4 changed files with 34 additions and 1 deletions
|
@ -69,7 +69,7 @@ JS_DEFINE_NATIVE_GETTER(Array::length_getter)
|
|||
auto* array = typed_this(vm, global_object);
|
||||
if (!array)
|
||||
return {};
|
||||
return Value(static_cast<i32>(array->indexed_properties().array_like_size()));
|
||||
return Value(array->indexed_properties().array_like_size());
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_SETTER(Array::length_setter)
|
||||
|
|
|
@ -333,6 +333,18 @@ void IndexedProperties::append_all(Object* this_object, const IndexedProperties&
|
|||
|
||||
void IndexedProperties::set_array_like_size(size_t new_size)
|
||||
{
|
||||
constexpr size_t length_setter_generic_storage_threshold = 4 * MiB;
|
||||
auto current_array_like_size = array_like_size();
|
||||
|
||||
// We can't use simple storage for lengths that don't fit in an i32.
|
||||
// Also, to avoid gigantic unused storage allocations, let's put an (arbitrary) 4M cap on simple storage here.
|
||||
// This prevents something like "a = []; a.length = 0x80000000;" from allocating 2G entries.
|
||||
if (m_storage->is_simple_storage()
|
||||
&& (new_size > NumericLimits<i32>::max()
|
||||
|| (current_array_like_size < length_setter_generic_storage_threshold && new_size > length_setter_generic_storage_threshold))) {
|
||||
switch_to_generic_storage();
|
||||
}
|
||||
|
||||
m_storage->set_array_like_size(new_size);
|
||||
}
|
||||
|
||||
|
|
|
@ -122,6 +122,17 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
explicit Value(unsigned long value)
|
||||
{
|
||||
if (value > NumericLimits<i32>::max()) {
|
||||
m_value.as_double = static_cast<double>(value);
|
||||
m_type = Type::Double;
|
||||
} else {
|
||||
m_value.as_i32 = static_cast<i32>(value);
|
||||
m_type = Type::Int32;
|
||||
}
|
||||
}
|
||||
|
||||
explicit Value(unsigned value)
|
||||
{
|
||||
if (value > NumericLimits<i32>::max()) {
|
||||
|
|
|
@ -34,4 +34,14 @@ describe("normal behavior", () => {
|
|||
a.length = true;
|
||||
expect(a).toHaveLength(1);
|
||||
});
|
||||
|
||||
test("setting a huge array length", () => {
|
||||
var a = [];
|
||||
a.length = 0x80000000;
|
||||
expect(a.length).toEqual(0x80000000);
|
||||
|
||||
var b = [];
|
||||
b.length = 0x80000001;
|
||||
expect(b.length).toEqual(0x80000001);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue