From 271eeadf2568fbe56d4c60c991a721c7e53481cb Mon Sep 17 00:00:00 2001 From: Idan Horowitz Date: Fri, 18 Jun 2021 22:35:53 +0300 Subject: [PATCH] LibJS: Bring FlattenIntoArray closer to the specification This fixes the incorrect exception order and missing exception checks that were caused by the implementation not conforming exactly to the specification. --- .../LibJS/Runtime/ArrayPrototype.cpp | 52 +++++++++++-------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/Userland/Libraries/LibJS/Runtime/ArrayPrototype.cpp b/Userland/Libraries/LibJS/Runtime/ArrayPrototype.cpp index f0aff26ef4..621822718a 100644 --- a/Userland/Libraries/LibJS/Runtime/ArrayPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/ArrayPrototype.cpp @@ -1303,12 +1303,10 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::keys) } // 23.1.3.10.1 FlattenIntoArray ( target, source, sourceLen, start, depth [ , mapperFunction [ , thisArg ] ] ), https://tc39.es/ecma262/#sec-flattenintoarray -static size_t flatten_into_array(VM& vm, GlobalObject& global_object, Array& new_array, Object& array, size_t target_index, double depth, Function* mapper_func = {}, Value this_arg = {}) +static size_t flatten_into_array(GlobalObject& global_object, Object& new_array, Object& array, size_t array_length, size_t target_index, double depth, Function* mapper_func = {}, Value this_arg = {}) { VERIFY(!mapper_func || (!this_arg.is_empty() && depth == 1)); - auto array_length = length_of_array_like(global_object, array); - if (vm.exception()) - return {}; + auto& vm = global_object.vm(); for (size_t j = 0; j < array_length; ++j) { auto value_exists = array.has_property(j); @@ -1328,20 +1326,25 @@ static size_t flatten_into_array(VM& vm, GlobalObject& global_object, Array& new } if (depth > 0 && value.is_array(global_object)) { - target_index = flatten_into_array(vm, global_object, new_array, value.as_array(), target_index, depth - 1); + auto length = length_of_array_like(global_object, value.as_array()); + if (vm.exception()) + return {}; + target_index = flatten_into_array(global_object, new_array, value.as_array(), length, target_index, depth - 1); if (vm.exception()) return {}; continue; } + + if (target_index >= MAX_ARRAY_LIKE_INDEX) { + vm.throw_exception(global_object, ErrorType::InvalidIndex); + return {}; + } + + new_array.put(target_index, value); if (vm.exception()) return {}; - if (!value.is_empty()) { - new_array.put(target_index, value); - if (vm.exception()) - return {}; - ++target_index; - } + ++target_index; } return target_index; } @@ -1353,20 +1356,21 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::flat) if (!this_object) return {}; - auto* new_array = Array::create(global_object); + auto length = length_of_array_like(global_object, *this_object); + if (vm.exception()) + return {}; double depth = 1; - if (vm.argument_count() > 0) { - auto depth_argument = vm.argument(0); - if (!depth_argument.is_undefined()) { - auto depth_num = depth_argument.to_integer_or_infinity(global_object); - if (vm.exception()) - return {}; - depth = max(depth_num, 0.0); - } + if (!vm.argument(0).is_undefined()) { + auto depth_num = vm.argument(0).to_integer_or_infinity(global_object); + if (vm.exception()) + return {}; + depth = max(depth_num, 0.0); } - flatten_into_array(vm, global_object, *new_array, *this_object, 0, depth); + auto* new_array = Array::create(global_object); + + flatten_into_array(global_object, *new_array, *this_object, length, 0, depth); if (vm.exception()) return {}; return new_array; @@ -1379,6 +1383,10 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::flat_map) if (!this_object) return {}; + auto length = length_of_array_like(global_object, *this_object); + if (vm.exception()) + return {}; + auto* mapper_function = callback_from_args(global_object, "flatMap"); if (!mapper_function) return {}; @@ -1388,7 +1396,7 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::flat_map) // FIXME: Use ArraySpeciesCreate. auto new_array = Array::create(global_object); - flatten_into_array(vm, global_object, *new_array, *this_object, 0, 1, mapper_function, this_argument); + flatten_into_array(global_object, *new_array, *this_object, length, 0, 1, mapper_function, this_argument); if (vm.exception()) return {};