From fec5933a3db4b2bd7657152d14a33e7439c77a87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20B=C3=A1tyai?= Date: Thu, 23 Jul 2015 18:09:19 +0200 Subject: [PATCH] Fix Array.prototype.push() and unshift() in case result length is larger than UINT_MAX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit JerryScript-DCO-1.0-Signed-off-by: Dániel Bátyai dbatyai.u-szeged@partner.samsung.com --- .../ecma-builtin-array-prototype.cpp | 73 +++++++----------- tests/jerry/array-prototype-push.js | 75 +++++++++++++++++++ tests/jerry/array.js | 25 ------- 3 files changed, 100 insertions(+), 73 deletions(-) create mode 100644 tests/jerry/array-prototype-push.js diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.cpp b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.cpp index 506be6fdd..0e9a35bf0 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.cpp +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.cpp @@ -57,19 +57,18 @@ */ static ecma_completion_value_t ecma_builtin_array_prototype_helper_set_length (ecma_object_t *object, /**< object*/ - uint32_t length) /**< new length */ + ecma_number_t length) /**< new length */ { ecma_completion_value_t ret_value; ecma_string_t *magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); ecma_number_t *len_p = ecma_alloc_number (); - *len_p = ecma_uint32_to_number (length); + *len_p = length; ret_value = ecma_op_object_put (object, magic_string_length_p, ecma_make_number_value (len_p), true), - ecma_dealloc_number (len_p); ecma_deref_ecma_string (magic_string_length_p); @@ -271,7 +270,7 @@ ecma_builtin_array_prototype_object_concat (ecma_value_t this_arg, /**< this arg if (ecma_is_completion_value_empty (ret_value)) { ECMA_TRY_CATCH (set_length_value, - ecma_builtin_array_prototype_helper_set_length (new_array_p, new_length), + ecma_builtin_array_prototype_helper_set_length (new_array_p, ecma_uint32_to_number (new_length)), ret_value); ret_value = new_array; ECMA_FINALIZE (set_length_value); @@ -490,7 +489,7 @@ ecma_builtin_array_prototype_object_pop (ecma_value_t this_arg) /**< this argume { /* 4.a */ ECMA_TRY_CATCH (set_length_value, - ecma_builtin_array_prototype_helper_set_length (obj_p, 0), + ecma_builtin_array_prototype_helper_set_length (obj_p, ECMA_NUMBER_ZERO), ret_value); /* 4.b */ @@ -512,7 +511,7 @@ ecma_builtin_array_prototype_object_pop (ecma_value_t this_arg) /**< this argume /* 5.d */ ECMA_TRY_CATCH (set_length_value, - ecma_builtin_array_prototype_helper_set_length (obj_p, len), + ecma_builtin_array_prototype_helper_set_length (obj_p, ecma_uint32_to_number (len)), ret_value); ret_value = ecma_make_normal_completion_value (ecma_copy_value (get_value, true)); @@ -563,61 +562,38 @@ ecma_builtin_array_prototype_object_push (ecma_value_t this_arg, /**< this argum /* 3. */ ECMA_OP_TO_NUMBER_TRY_CATCH (length_var, length_value, ret_value); - uint32_t n = ecma_number_to_uint32 (length_var); + ecma_number_t n = ecma_uint32_to_number (ecma_number_to_uint32 (length_var)); /* 5. */ for (uint32_t index = 0; - index < arguments_number; + index < arguments_number && ecma_is_completion_value_empty (ret_value); index++, n++) { /* 5.a */ ecma_value_t e_value = argument_list_p[index]; /* 5.b */ - ecma_string_t *n_str_p = ecma_new_ecma_string_from_uint32 (n); + ecma_string_t *n_str_p = ecma_new_ecma_string_from_number (n); - ecma_completion_value_t completion = ecma_op_object_put (obj_p, n_str_p, e_value, true); + ECMA_TRY_CATCH (put_value, ecma_op_object_put (obj_p, n_str_p, e_value, true), ret_value); + ECMA_FINALIZE (put_value); ecma_deref_ecma_string (n_str_p); - - if (unlikely (ecma_is_completion_value_throw (completion))) - { - ret_value = completion; - break; - } - else - { - JERRY_ASSERT (ecma_is_completion_value_normal (completion)); - ecma_free_completion_value (completion); - } } /* 6. */ if (ecma_is_completion_value_empty (ret_value)) { - ecma_number_t *num_length_p = ecma_alloc_number (); - *num_length_p = ecma_uint32_to_number (n); + ECMA_TRY_CATCH (set_length_value, + ecma_builtin_array_prototype_helper_set_length (obj_p, n), + ret_value); - ecma_value_t num_length_value = ecma_make_number_value (num_length_p); + ecma_number_t *ret_num_p = ecma_alloc_number (); + *ret_num_p = n; - ecma_completion_value_t completion = ecma_op_object_put (obj_p, - length_str_p, - num_length_value, - true); + ret_value = ecma_make_normal_completion_value (ecma_make_number_value (ret_num_p)); - if (unlikely (ecma_is_completion_value_throw (completion))) - { - ret_value = completion; - - ecma_dealloc_number (num_length_p); - } - else - { - JERRY_ASSERT (ecma_is_completion_value_normal (completion)); - ecma_free_completion_value (completion); - - ret_value = ecma_make_normal_completion_value (num_length_value); - } + ECMA_FINALIZE (set_length_value) } ECMA_OP_TO_NUMBER_FINALIZE (length_var); @@ -763,7 +739,7 @@ ecma_builtin_array_prototype_object_shift (ecma_value_t this_arg) /**< this argu if (len == 0) { ECMA_TRY_CATCH (set_length_value, - ecma_builtin_array_prototype_helper_set_length (obj_p, 0), + ecma_builtin_array_prototype_helper_set_length (obj_p, ECMA_NUMBER_ZERO), ret_value); ret_value = ecma_make_simple_completion_value (ECMA_SIMPLE_VALUE_UNDEFINED); @@ -818,7 +794,7 @@ ecma_builtin_array_prototype_object_shift (ecma_value_t this_arg) /**< this argu /* 9. */ ECMA_TRY_CATCH (set_length_value, - ecma_builtin_array_prototype_helper_set_length (obj_p, len), + ecma_builtin_array_prototype_helper_set_length (obj_p, ecma_uint32_to_number (len)), ret_value); /* 10. */ ret_value = ecma_make_normal_completion_value (ecma_copy_value (first_value, true)); @@ -1651,7 +1627,7 @@ ecma_builtin_array_prototype_object_splice (ecma_value_t this_arg, /**< this arg if (ecma_is_completion_value_empty (ret_value)) { ECMA_TRY_CATCH (set_length_value, - ecma_builtin_array_prototype_helper_set_length (obj_p, new_len), + ecma_builtin_array_prototype_helper_set_length (obj_p, ecma_uint32_to_number (new_len)), ret_value); ECMA_FINALIZE (set_length_value); @@ -1714,7 +1690,8 @@ ecma_builtin_array_prototype_object_unshift (ecma_value_t this_arg, /**< this ar /* 6.a */ ecma_string_t *from_str_p = ecma_new_ecma_string_from_uint32 (k - 1); /* 6.b */ - ecma_string_t *to_str_p = ecma_new_ecma_string_from_uint32 (k + args_number - 1); + ecma_number_t new_idx = ecma_uint32_to_number (k) + ecma_uint32_to_number (args_number) - 1; + ecma_string_t *to_str_p = ecma_new_ecma_string_from_number (new_idx); /* 6.c */ if (ecma_op_object_get_property (obj_p, from_str_p) != NULL) @@ -1751,13 +1728,13 @@ ecma_builtin_array_prototype_object_unshift (ecma_value_t this_arg, /**< this ar if (ecma_is_completion_value_empty (ret_value)) { + ecma_number_t new_len = ecma_uint32_to_number (len) + ecma_uint32_to_number (args_number); /* 10. */ ECMA_TRY_CATCH (set_length_value, - ecma_builtin_array_prototype_helper_set_length (obj_p, len + args_number), + ecma_builtin_array_prototype_helper_set_length (obj_p, new_len), ret_value); - ecma_number_t *num_p = ecma_alloc_number (); - *num_p = ecma_uint32_to_number (len + args_number); + *num_p = new_len; ret_value = ecma_make_normal_completion_value (ecma_make_number_value (num_p)); ECMA_FINALIZE (set_length_value); diff --git a/tests/jerry/array-prototype-push.js b/tests/jerry/array-prototype-push.js new file mode 100644 index 000000000..ebaebf659 --- /dev/null +++ b/tests/jerry/array-prototype-push.js @@ -0,0 +1,75 @@ +// Copyright 2015 Samsung Electronics Co., Ltd. +// Copyright 2015 University of Szeged. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var len; +var d = []; +assert (d.length === 0); +len = d.push(); +assert (d.length === 0); +assert (d.length === len); +len = d.push(1); +assert (d.length === 1); +assert (d.length === len); +len = d.push(2); +assert (d.length === 2); +assert (d.length === len); +len = d.push('a'); +assert (d.length === 3); +assert (d.length === len); +len = d.push('b', 'c', 3); +assert (d.length == 6); +assert (d.length === len); +assert (d[0] === 1); +assert (d[1] === 2); +assert (d[2] === 'a'); +assert (d[3] === 'b'); +assert (d[4] === 'c'); +assert (d[5] === 3); + +var a = []; +a.length = 4294967294; +assert(a.push("x") === 4294967295); +assert(a.length === 4294967295); +assert(a[4294967294] === "x"); + +try { + a.push("y"); + assert(false); +} catch (e) { + assert (e instanceof RangeError); +} +assert(a.length === 4294967295) + + +var o = { length : 4294967294, push : Array.prototype.push }; +assert(o.push("x") === 4294967295); +assert(o.length === 4294967295); +assert(o[4294967294] === "x"); + +try { + assert(o.push("y") === 4294967296); +} catch (e) { + assert(false); +} +assert(o.length === 4294967296); +assert(o[4294967295] === "y"); + +try { + assert(o.push("z") === 1); +} catch (e) { + assert(false); +} +assert(o.length === 1); +assert(o[0] === "z"); diff --git a/tests/jerry/array.js b/tests/jerry/array.js index f00f3c8e6..14c2339d6 100644 --- a/tests/jerry/array.js +++ b/tests/jerry/array.js @@ -81,28 +81,3 @@ assert (c[3] === '3'); b[0] = 1; c[0] += b[0]; assert (c[0] == 1); - -var len; -var d = []; -assert (d.length === 0); -len = d.push(); -assert (d.length === 0); -assert (d.length === len); -len = d.push(1); -assert (d.length === 1); -assert (d.length === len); -len = d.push(2); -assert (d.length === 2); -assert (d.length === len); -len = d.push('a'); -assert (d.length === 3); -assert (d.length === len); -len = d.push('b', 'c', 3); -assert (d.length == 6); -assert (d.length === len); -assert (d[0] === 1); -assert (d[1] === 2); -assert (d[2] === 'a'); -assert (d[3] === 'b'); -assert (d[4] === 'c'); -assert (d[5] === 3);