LibJS: Allow setting the length of an object with prototype Array
Before this it would always go through the native setter thus modifying the array but now you can set length to anything
This commit is contained in:
parent
b38fb418f8
commit
b1441a47b1
Notes:
sideshowbarker
2024-07-18 11:28:44 +09:00
Author: https://github.com/davidot Commit: https://github.com/SerenityOS/serenity/commit/b1441a47b16 Pull-request: https://github.com/SerenityOS/serenity/pull/8245
2 changed files with 92 additions and 7 deletions
|
@ -65,25 +65,50 @@ Array* Array::typed_this(VM& vm, GlobalObject& global_object)
|
|||
|
||||
JS_DEFINE_NATIVE_GETTER(Array::length_getter)
|
||||
{
|
||||
auto* array = typed_this(vm, global_object);
|
||||
if (!array)
|
||||
auto* this_object = vm.this_value(global_object).to_object(global_object);
|
||||
if (!this_object)
|
||||
return {};
|
||||
return Value(array->indexed_properties().array_like_size());
|
||||
|
||||
// TODO: could be incorrect if receiver/this_value is fixed or changed
|
||||
if (!this_object->is_array()) {
|
||||
Value val = this_object->get_own_property(vm.names.length.to_string_or_symbol(), this_object);
|
||||
if (vm.exception())
|
||||
return {};
|
||||
return val;
|
||||
}
|
||||
|
||||
return Value(this_object->indexed_properties().array_like_size());
|
||||
}
|
||||
|
||||
JS_DEFINE_NATIVE_SETTER(Array::length_setter)
|
||||
{
|
||||
auto* array = typed_this(vm, global_object);
|
||||
if (!array)
|
||||
auto* this_object = vm.this_value(global_object).to_object(global_object);
|
||||
if (!this_object)
|
||||
return;
|
||||
|
||||
// TODO: could be incorrect if receiver/this_value is fixed or changed
|
||||
if (!this_object->is_array()) {
|
||||
this_object->define_property(vm.names.length.to_string_or_symbol(), value, default_attributes);
|
||||
if (vm.exception())
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
auto length = value.to_number(global_object);
|
||||
if (vm.exception())
|
||||
return;
|
||||
if (length.is_nan() || length.is_infinity() || length.as_double() < 0) {
|
||||
|
||||
u32 val = length.as_double();
|
||||
|
||||
if (val != length.as_double()
|
||||
|| length.is_nan()
|
||||
|| length.is_infinity()
|
||||
|| length.as_double() < 0
|
||||
|| length.as_double() > NumericLimits<u32>::max()) {
|
||||
vm.throw_exception<RangeError>(global_object, ErrorType::InvalidLength, "array");
|
||||
return;
|
||||
}
|
||||
array->indexed_properties().set_array_like_size(length.as_double());
|
||||
this_object->indexed_properties().set_array_like_size(val);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -55,3 +55,63 @@ describe("normal behavior", () => {
|
|||
expect(a[1]).toEqual(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe("behavior when obj has Array prototype", () => {
|
||||
function ArrExtend() {}
|
||||
ArrExtend.prototype = [10, 11, 12];
|
||||
|
||||
test("Has the properties from prototype", () => {
|
||||
var arr = new ArrExtend();
|
||||
expect(arr.length).toEqual(3);
|
||||
expect(arr[0]).toEqual(10);
|
||||
expect(arr[1]).toEqual(11);
|
||||
expect(arr[2]).toEqual(12);
|
||||
});
|
||||
|
||||
test("Can override length to any value", () => {
|
||||
[null, "Hello friends :^)", -6, 0].forEach(value => {
|
||||
var arr = new ArrExtend();
|
||||
arr.length = value;
|
||||
expect(arr.length).toEqual(value);
|
||||
|
||||
// should not wipe high values
|
||||
expect(arr[0]).toEqual(10);
|
||||
expect(arr[1]).toEqual(11);
|
||||
expect(arr[2]).toEqual(12);
|
||||
});
|
||||
});
|
||||
|
||||
test("Can call array methods", () => {
|
||||
var arr = new ArrExtend();
|
||||
arr.push(1);
|
||||
expect(arr.length).toEqual(4);
|
||||
expect(arr[3]).toEqual(1);
|
||||
});
|
||||
|
||||
test("If length overwritten uses that value", () => {
|
||||
[null, "Hello friends :^)", -6, 0].forEach(value => {
|
||||
var arr = new ArrExtend();
|
||||
arr.length = value;
|
||||
expect(arr.length).toEqual(value);
|
||||
|
||||
arr.push(99);
|
||||
expect(arr.length).toEqual(1);
|
||||
expect(arr[0]).toEqual(99);
|
||||
|
||||
// should not wipe higher value
|
||||
expect(arr[1]).toEqual(11);
|
||||
expect(arr[2]).toEqual(12);
|
||||
|
||||
arr.push(100);
|
||||
|
||||
expect(arr.length).toEqual(2);
|
||||
expect(arr[1]).toEqual(100);
|
||||
|
||||
arr.length = 0;
|
||||
// should not wipe values since we are not an array
|
||||
expect(arr[0]).toEqual(99);
|
||||
expect(arr[1]).toEqual(100);
|
||||
expect(arr[2]).toEqual(12);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue