From c6f22a9683be8632fe1e2e4281af32eda18c7f0d Mon Sep 17 00:00:00 2001 From: Zidong Jiang Date: Tue, 7 Mar 2017 07:37:19 +0800 Subject: [PATCH] Make sure the size arg of alloc will not overflow (#1618) Also make sure the bytelength = arraylength << shift will not overflow Fix issue #1616 JerryScript-DCO-1.0-Signed-off-by: Zidong Jiang zidong.jiang@intel.com --- .../ecma-builtin-typedarray-prototype.c | 42 ++++-- .../ecma/operations/ecma-arraybuffer-object.c | 6 + .../ecma/operations/ecma-typedarray-object.c | 141 +++++++++++------- .../es2015/regression-test-issue-1616.js | 27 ++++ 4 files changed, 150 insertions(+), 66 deletions(-) create mode 100644 tests/jerry/es2015/regression-test-issue-1616.js diff --git a/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.c b/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.c index b2e39f648..069093401 100644 --- a/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.c +++ b/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.c @@ -321,6 +321,12 @@ ecma_builtin_typedarray_prototype_map (ecma_value_t this_arg, /**< this argument ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); ecma_value_t new_typedarray = ecma_op_create_typedarray_with_type_and_length (obj_p, len); + + if (ECMA_IS_VALUE_ERROR (new_typedarray)) + { + return new_typedarray; + } + ecma_object_t *new_obj_p = ecma_get_object_from_value (new_typedarray); for (uint32_t index = 0; index < len && ecma_is_value_empty (ret_value); index++) @@ -331,7 +337,7 @@ ecma_builtin_typedarray_prototype_map (ecma_value_t this_arg, /**< this argument ECMA_TRY_CATCH (mapped_value, ecma_op_function_call (func_object_p, cb_this_arg, call_args, 3), ret_value); - ecma_value_t set_status = ecma_op_typedarray_set_index_prop (new_obj_p, index, mapped_value); + bool set_status = ecma_op_typedarray_set_index_prop (new_obj_p, index, mapped_value); if (!set_status) { @@ -574,25 +580,33 @@ ecma_builtin_typedarray_prototype_filter (ecma_value_t this_arg, /**< this argum if (ecma_is_value_empty (ret_value)) { ecma_value_t new_typedarray = ecma_op_create_typedarray_with_type_and_length (obj_p, pass_num); - ecma_object_t *new_obj_p = ecma_get_object_from_value (new_typedarray); - for (uint32_t index = 0; index < pass_num && ecma_is_value_empty (ret_value); index++) - { - ecma_value_t set_status = ecma_op_typedarray_set_index_prop (new_obj_p, index, *(pass_value_list + index)); - - if (!set_status) - { - ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("error in typedarray set")); - } - } - - if (ecma_is_value_empty (ret_value)) + if (ECMA_IS_VALUE_ERROR (new_typedarray)) { ret_value = new_typedarray; } else { - ecma_free_value (new_typedarray); + ecma_object_t *new_obj_p = ecma_get_object_from_value (new_typedarray); + + for (uint32_t index = 0; index < pass_num && ecma_is_value_empty (ret_value); index++) + { + bool set_status = ecma_op_typedarray_set_index_prop (new_obj_p, index, *(pass_value_list + index)); + + if (!set_status) + { + ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("error in typedarray set")); + } + } + + if (ecma_is_value_empty (ret_value)) + { + ret_value = new_typedarray; + } + else + { + ecma_free_value (new_typedarray); + } } } diff --git a/jerry-core/ecma/operations/ecma-arraybuffer-object.c b/jerry-core/ecma/operations/ecma-arraybuffer-object.c index 8e1b1d262..548c2c3c6 100644 --- a/jerry-core/ecma/operations/ecma-arraybuffer-object.c +++ b/jerry-core/ecma/operations/ecma-arraybuffer-object.c @@ -21,6 +21,7 @@ #include "ecma-gc.h" #include "ecma-globals.h" #include "ecma-helpers.h" +#include "jmem.h" #ifndef CONFIG_DISABLE_ARRAYBUFFER_BUILTIN @@ -68,6 +69,11 @@ ecma_op_create_arraybuffer_object (const ecma_value_t *arguments_list_p, /**< li } } + if (length > UINT32_MAX - sizeof (ecma_extended_object_t) - JMEM_ALIGNMENT + 1) + { + return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid ArrayBuffer length.")); + } + ecma_object_t *object_p = ecma_arraybuffer_new_object (length); return ecma_make_object_value (object_p); diff --git a/jerry-core/ecma/operations/ecma-typedarray-object.c b/jerry-core/ecma/operations/ecma-typedarray-object.c index f43025b06..792388b6d 100644 --- a/jerry-core/ecma/operations/ecma-typedarray-object.c +++ b/jerry-core/ecma/operations/ecma-typedarray-object.c @@ -205,18 +205,28 @@ set_typedarray_element (lit_utf8_byte_t *dst, /**< the location in the internal * * See also: ES2015 22.2.1.2.1 * - * @return pointer to the new typedarray object + * @return ecma value of the new typedarray object + * Returned value must be freed with ecma_free_value */ -static ecma_object_t * +static ecma_value_t ecma_typedarray_create_object_with_length (ecma_length_t array_length, /**< length of the typedarray */ ecma_object_t *proto_p, /**< prototype object */ uint8_t element_size_shift, /**< the size shift of the element length */ lit_magic_string_id_t class_id) /**< class name of the typedarray */ { + if (array_length > (UINT32_MAX >> element_size_shift)) + { + return ecma_raise_range_error (ECMA_ERR_MSG ("Maximum typedarray size is reached.")); + } + ecma_length_t byte_length = array_length << element_size_shift; - ecma_value_t new_arraybuffer_p = ecma_make_object_value (ecma_arraybuffer_new_object (byte_length)); + if (byte_length > UINT32_MAX - sizeof (ecma_extended_object_t) - JMEM_ALIGNMENT + 1) + { + return ecma_raise_range_error (ECMA_ERR_MSG ("Maximum typedarray size is reached.")); + } + ecma_value_t new_arraybuffer_p = ecma_make_object_value (ecma_arraybuffer_new_object (byte_length)); ecma_object_t *object_p = ecma_create_object (proto_p, sizeof (ecma_extended_object_t), ECMA_OBJECT_TYPE_PSEUDO_ARRAY); @@ -229,7 +239,7 @@ ecma_typedarray_create_object_with_length (ecma_length_t array_length, /**< leng ecma_free_value (new_arraybuffer_p); - return object_p; + return ecma_make_object_value (object_p); } /* !ecma_typedarray_create_object_with_length */ /** @@ -237,9 +247,10 @@ ecma_typedarray_create_object_with_length (ecma_length_t array_length, /**< leng * * See also: ES2015 22.2.1.5 * - * @return pointer to the new typedarray object + * @return ecma value of the new typedarray object + * Returned value must be freed with ecma_free_value */ -static ecma_object_t * +static ecma_value_t ecma_typedarray_create_object_with_buffer (ecma_object_t *arraybuffer_p, /**< the arraybuffer inside */ ecma_length_t byte_offset, /**< the byte offset of the arraybuffer */ ecma_length_t array_length, /**< length of the typedarray */ @@ -248,6 +259,7 @@ ecma_typedarray_create_object_with_buffer (ecma_object_t *arraybuffer_p, /**< th lit_magic_string_id_t class_id) /**< class name of the typedarray */ { ecma_object_t *object_p; + if (byte_offset == 0 && array_length == ecma_arraybuffer_get_length (arraybuffer_p) >> element_size_shift) { object_p = ecma_create_object (proto_p, @@ -260,7 +272,7 @@ ecma_typedarray_create_object_with_buffer (ecma_object_t *arraybuffer_p, /**< th ext_object_p->u.pseudo_array.extra_info = element_size_shift; ext_object_p->u.pseudo_array.u2.arraybuffer = ecma_make_object_value (arraybuffer_p); - return object_p; + return ecma_make_object_value (object_p); } object_p = ecma_create_object (proto_p, @@ -277,7 +289,7 @@ ecma_typedarray_create_object_with_buffer (ecma_object_t *arraybuffer_p, /**< th typedarray_info_p->array_length = array_length; typedarray_info_p->byte_offset = byte_offset; - return object_p; + return ecma_make_object_value (object_p); } /* ecma_typedarray_create_object_with_buffer */ /** @@ -285,9 +297,10 @@ ecma_typedarray_create_object_with_buffer (ecma_object_t *arraybuffer_p, /**< th * * See also: ES2015 22.2.1.3 * - * @return pointer to the new typedarray object + * @return ecma value of the new typedarray object + * Returned value must be freed with ecma_free_value */ -static ecma_object_t * +static ecma_value_t ecma_typedarray_create_object_with_typedarray (ecma_object_t *typedarray_p, /**< a typedarray object */ ecma_object_t *proto_p, /**< prototype object */ uint8_t element_size_shift, /**< the size shift of the element length */ @@ -306,7 +319,18 @@ ecma_typedarray_create_object_with_typedarray (ecma_object_t *typedarray_p, /**< } else { + if (array_length > (UINT32_MAX >> element_size_shift)) + { + return ecma_raise_range_error (ECMA_ERR_MSG ("Maximum typedarray size is reached.")); + } + ecma_length_t byte_length = array_length << element_size_shift; + + if (byte_length > UINT32_MAX - sizeof (ecma_extended_object_t) - JMEM_ALIGNMENT + 1) + { + return ecma_raise_range_error (ECMA_ERR_MSG ("Maximum typedarray size is reached.")); + } + arraybuffer_p = ecma_arraybuffer_new_object (byte_length); lit_utf8_byte_t *src_buf = ecma_arraybuffer_get_buffer (src_arraybuffer_p); lit_utf8_byte_t *dst_buf = ecma_arraybuffer_get_buffer (arraybuffer_p); @@ -324,16 +348,16 @@ ecma_typedarray_create_object_with_typedarray (ecma_object_t *typedarray_p, /**< } } - ecma_object_t *object_p = ecma_typedarray_create_object_with_buffer (arraybuffer_p, - 0, - array_length, - proto_p, - element_size_shift, - class_id); + ecma_value_t obj = ecma_typedarray_create_object_with_buffer (arraybuffer_p, + 0, + array_length, + proto_p, + element_size_shift, + class_id); ecma_deref_object (arraybuffer_p); - return object_p; + return obj; } /* ecma_typedarray_create_object_with_typedarray */ /** @@ -341,7 +365,7 @@ ecma_typedarray_create_object_with_typedarray (ecma_object_t *typedarray_p, /**< * * See also: ES2015 22.2.2.1 * - * @return ecma value + * @return ecma value of the new typedarray object * Returned value must be freed with ecma_free_value */ ecma_value_t @@ -364,11 +388,11 @@ ecma_op_typedarray_from (ecma_value_t items_val, /**< the source array-like obje } /* 10 */ - ECMA_TRY_CATCH (arraylike_val, + ECMA_TRY_CATCH (arraylike, ecma_op_to_object (items_val), ret_value); - ecma_object_t *arraylike_p = ecma_get_object_from_value (arraylike_val); + ecma_object_t *arraylike_p = ecma_get_object_from_value (arraylike); /* 12 */ ecma_string_t *magic_string_length_p = ecma_new_ecma_length_string (); @@ -382,10 +406,17 @@ ecma_op_typedarray_from (ecma_value_t items_val, /**< the source array-like obje uint32_t len = ecma_number_to_uint32 (len_number); /* 14 */ - ecma_object_t *new_typedarray_p = ecma_typedarray_create_object_with_length (len, - proto_p, - element_size_shift, - class_id); + ecma_value_t new_typedarray = ecma_typedarray_create_object_with_length (len, + proto_p, + element_size_shift, + class_id); + + if (ECMA_IS_VALUE_ERROR (new_typedarray)) + { + ret_value = ecma_copy_value (new_typedarray); + } + + ecma_object_t *new_typedarray_p = ecma_get_object_from_value (new_typedarray); /* 17 */ ecma_value_t current_index; @@ -446,7 +477,7 @@ ecma_op_typedarray_from (ecma_value_t items_val, /**< the source array-like obje ECMA_OP_TO_NUMBER_FINALIZE (len_number); ECMA_FINALIZE (len_value); ecma_deref_ecma_string (magic_string_length_p); - ECMA_FINALIZE (arraylike_val); + ECMA_FINALIZE (arraylike); return ret_value; } /* ecma_op_typedarray_from */ @@ -539,7 +570,7 @@ ecma_typedarray_get_offset (ecma_object_t *typedarray_p) /**< the pointer to the * extend_part * typedarray_info * - * @return ecma value + * @return ecma value of the new typedarray object * Returned value must be freed with ecma_free_value */ ecma_value_t @@ -556,7 +587,7 @@ ecma_op_create_typedarray (const ecma_value_t *arguments_list_p, /**< the arg li if (arguments_list_len == 0) { /* 22.2.1.1 */ - ret = ecma_make_object_value (ecma_typedarray_create_object_with_length (0, proto_p, element_size_shift, class_id)); + ret = ecma_typedarray_create_object_with_length (0, proto_p, element_size_shift, class_id); } else if (!ecma_is_value_object (arguments_list_p[0])) { @@ -576,10 +607,10 @@ ecma_op_create_typedarray (const ecma_value_t *arguments_list_p, /**< the arg li } else { - ret = ecma_make_object_value (ecma_typedarray_create_object_with_length (length, - proto_p, - element_size_shift, - class_id)); + ret = ecma_typedarray_create_object_with_length (length, + proto_p, + element_size_shift, + class_id); } ECMA_OP_TO_NUMBER_FINALIZE (num); @@ -590,10 +621,10 @@ ecma_op_create_typedarray (const ecma_value_t *arguments_list_p, /**< the arg li { /* 22.2.1.3 */ ecma_object_t *typedarray_p = ecma_get_object_from_value (arguments_list_p[0]); - ret = ecma_make_object_value (ecma_typedarray_create_object_with_typedarray (typedarray_p, - proto_p, - element_size_shift, - class_id)); + ret = ecma_typedarray_create_object_with_typedarray (typedarray_p, + proto_p, + element_size_shift, + class_id); } else if (ecma_is_arraybuffer (arguments_list_p[0])) { @@ -638,6 +669,12 @@ ecma_op_create_typedarray (const ecma_value_t *arguments_list_p, /**< the arg li ECMA_OP_TO_NUMBER_TRY_CATCH (num3, arg3, ret); int32_t new_length = ecma_number_to_int32 (num3); new_length = (new_length > 0) ? new_length : 0; + + if ((uint32_t) new_length > (UINT32_MAX >> element_size_shift)) + { + ret = ecma_raise_range_error (ECMA_ERR_MSG ("Maximum typedarray size is reached.")); + } + new_byte_length = (ecma_length_t) new_length << element_size_shift; if (new_byte_length + offset > buf_byte_length) @@ -651,12 +688,12 @@ ecma_op_create_typedarray (const ecma_value_t *arguments_list_p, /**< the arg li if (ecma_is_value_empty (ret)) { ecma_length_t array_length = new_byte_length >> element_size_shift; - ret = ecma_make_object_value (ecma_typedarray_create_object_with_buffer (arraybuffer_p, - offset, - array_length, - proto_p, - element_size_shift, - class_id)); + ret = ecma_typedarray_create_object_with_buffer (arraybuffer_p, + offset, + array_length, + proto_p, + element_size_shift, + class_id); } } @@ -665,10 +702,10 @@ ecma_op_create_typedarray (const ecma_value_t *arguments_list_p, /**< the arg li else { /* 22.2.1.4 */ - ecma_value_t undef_val = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); + ecma_value_t undef = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); ret = ecma_op_typedarray_from (arguments_list_p[0], - undef_val, - undef_val, + undef, + undef, proto_p, element_size_shift, class_id); @@ -825,9 +862,9 @@ ecma_op_typedarray_set_index_prop (ecma_object_t *obj_p, /**< a TypedArray objec return false; } - ecma_value_t error_val = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); + ecma_value_t error = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); - ECMA_OP_TO_NUMBER_TRY_CATCH (value_num, value, error_val); + ECMA_OP_TO_NUMBER_TRY_CATCH (value_num, value, error); ecma_object_t *arraybuffer_p = ecma_typedarray_get_arraybuffer (obj_p); ecma_length_t offset = ecma_typedarray_get_offset (obj_p); @@ -839,7 +876,7 @@ ecma_op_typedarray_set_index_prop (ecma_object_t *obj_p, /**< a TypedArray objec ECMA_OP_TO_NUMBER_FINALIZE (value_num); - if (ecma_is_value_empty (error_val)) + if (ecma_is_value_empty (error)) { return true; } @@ -929,14 +966,14 @@ ecma_op_create_typedarray_with_type_and_length (ecma_object_t *obj_p, /**< Typed } } - ecma_object_t *new_obj_p = ecma_typedarray_create_object_with_length (array_length, - proto_p, - element_size_shift, - class_id); + ecma_value_t new_obj = ecma_typedarray_create_object_with_length (array_length, + proto_p, + element_size_shift, + class_id); ecma_deref_object (proto_p); - return ecma_make_object_value (new_obj_p); + return new_obj; } /* ecma_op_create_typedarray_with_type_and_length */ /** diff --git a/tests/jerry/es2015/regression-test-issue-1616.js b/tests/jerry/es2015/regression-test-issue-1616.js new file mode 100644 index 000000000..f08bd4d52 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-1616.js @@ -0,0 +1,27 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// 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 name = ""; + +try +{ + var a = new ArrayBuffer (0xfffffffe) +} +catch (e) +{ + name = e.name; +} + +assert(name === "RangeError"); +