Add missing isArray checks based on the ES11 standard (#3983)

Added checks to the following methods:
- ecma_builtin_json_stringify, ECMA-262 v11, 24.5.2
- ecma_builtin_json_internalize_property, ECMA-262 v11, 24.5.1.1

Fixes #3945
Fixes #3950

JerryScript-DCO-1.0-Signed-off-by: Adam Szilagyi aszilagy@inf.u-szeged.hu
This commit is contained in:
Szilagyi Adam 2020-07-10 16:06:27 +02:00 committed by GitHub
parent b90fa63255
commit dfabfe7a56
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 217 additions and 91 deletions

View File

@ -602,7 +602,11 @@ ecma_builtin_json_parse_value (ecma_json_token_t *token_p) /**< token argument *
} /* ecma_builtin_json_parse_value */
/**
* Abstract operation InternalizeJSONProperty defined in 24.3.1.1
* Abstract operation InternalizeJSONProperty
*
* See also:
* ECMA-262 v5, 24.3.1.1
* ECMA-262 v11, 24.5.1.1
*
* @return ecma value
* Returned value must be freed with ecma_free_value.
@ -628,48 +632,111 @@ ecma_builtin_json_internalize_property (ecma_object_t *reviver_p, /**< reviver f
/* 3. */
if (ecma_is_value_object (value))
{
/* 3.a */
ecma_value_t is_array = ecma_is_value_array (value);
#if ENABLED (JERRY_ESNEXT)
if (ECMA_IS_VALUE_ERROR (is_array))
{
ecma_free_value (value);
return is_array;
}
#endif /* ENABLED (JERRY_ESNEXT) */
ecma_object_t *object_p = ecma_get_object_from_value (value);
ecma_collection_t *props_p = ecma_op_object_get_property_names (object_p, ECMA_LIST_ENUMERABLE);
ecma_value_t *buffer_p = props_p->buffer_p;
/* 3.d.iii */
for (uint32_t i = 0; i < props_p->item_count; i++)
/* 3.c */
if (ecma_is_value_true (is_array))
{
ecma_string_t *property_name_p = ecma_get_string_from_value (buffer_p[i]);
/* 3.c.ii */
uint32_t len;
ecma_value_t to_len = ecma_op_object_get_length (object_p, &len);
/* 3.d.iii.1 */
ecma_value_t result = ecma_builtin_json_internalize_property (reviver_p, object_p, property_name_p);
/* 3.d.iii.2 */
if (ECMA_IS_VALUE_ERROR (result))
/* 3.c.iii */
if (ECMA_IS_VALUE_ERROR (to_len))
{
ecma_collection_free (props_p);
ecma_deref_object (object_p);
return result;
return to_len;
}
/* 3.d.iii.3 */
if (ecma_is_value_undefined (result))
/* 3.c.iv */
for (uint32_t i = 0; i < len; i++)
{
ecma_value_t delete_val = ecma_op_general_object_delete (object_p,
property_name_p,
false);
JERRY_ASSERT (ecma_is_value_boolean (delete_val));
}
/* 3.d.iii.4 */
else
{
ecma_builtin_json_define_value_property (object_p,
property_name_p,
result);
ecma_free_value (result);
ecma_string_t *prop_index = ecma_new_ecma_string_from_uint32 (i);
ecma_value_t new_element = ecma_builtin_json_internalize_property (reviver_p, object_p, prop_index);
if (ECMA_IS_VALUE_ERROR (new_element))
{
ecma_deref_ecma_string (prop_index);
ecma_deref_object (object_p);
return new_element;
}
if (ecma_is_value_undefined (new_element))
{
ecma_value_t delete_val = ecma_op_object_delete_by_uint32_index (object_p,
i,
false);
JERRY_ASSERT (ecma_is_value_boolean (delete_val));
}
else
{
ecma_builtin_json_define_value_property (object_p,
prop_index,
new_element);
ecma_free_value (new_element);
}
ecma_deref_ecma_string (prop_index);
}
}
/* 3.d */
else
{
ecma_collection_t *props_p = ecma_op_object_get_property_names (object_p, ECMA_LIST_ENUMERABLE);
ecma_collection_free (props_p);
JERRY_ASSERT (props_p != NULL);
ecma_value_t *buffer_p = props_p->buffer_p;
/* 3.d.iii */
for (uint32_t i = 0; i < props_p->item_count; i++)
{
ecma_string_t *property_name_p = ecma_get_string_from_value (buffer_p[i]);
/* 3.d.iii.1 */
ecma_value_t result = ecma_builtin_json_internalize_property (reviver_p, object_p, property_name_p);
/* 3.d.iii.2 */
if (ECMA_IS_VALUE_ERROR (result))
{
ecma_collection_free (props_p);
ecma_deref_object (object_p);
return result;
}
/* 3.d.iii.3 */
if (ecma_is_value_undefined (result))
{
ecma_value_t delete_val = ecma_op_general_object_delete (object_p,
property_name_p,
false);
JERRY_ASSERT (ecma_is_value_boolean (delete_val));
}
/* 3.d.iii.4 */
else
{
ecma_builtin_json_define_value_property (object_p,
property_name_p,
result);
ecma_free_value (result);
}
}
ecma_collection_free (props_p);
}
}
ecma_value_t arguments_list[2];
@ -677,10 +744,10 @@ ecma_builtin_json_internalize_property (ecma_object_t *reviver_p, /**< reviver f
arguments_list[1] = value;
/* 4. */
ecma_value_t ret_value = ecma_op_function_call (reviver_p,
ecma_make_object_value (holder_p),
arguments_list,
2);
ecma_value_t ret_value = ecma_op_function_call (reviver_p,
ecma_make_object_value (holder_p),
arguments_list,
2);
ecma_free_value (value);
return ret_value;
} /* ecma_builtin_json_internalize_property */
@ -1379,6 +1446,7 @@ ecma_builtin_json_stringify_no_opts (const ecma_value_t value) /**< value to str
*
* See also:
* ECMA-262 v5, 15.12.3
* ECMA-262 v11, 24.5.2
*
* @return ecma value
* Returned value must be freed with ecma_free_value.
@ -1406,80 +1474,99 @@ ecma_builtin_json_stringify (ecma_value_t this_arg, /**< 'this' argument */
context.replacer_function_p = obj_p;
}
/* 4.b */
else if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY)
else
{
context.property_list_p = ecma_new_collection ();
ecma_extended_object_t *array_object_p = (ecma_extended_object_t *) obj_p;
uint32_t array_length = array_object_p->u.array.length;
uint32_t index = 0;
ecma_value_t is_array = ecma_is_value_array (arg2);
/* 4.b.iii.5 */
while (index < array_length)
#if ENABLED (JERRY_ESNEXT)
if (ECMA_IS_VALUE_ERROR (is_array))
{
ecma_value_t value = ecma_op_object_get_by_uint32_index (obj_p, index);
return is_array;
}
#endif /* ENABLED (JERRY_ESNEXT) */
if (ECMA_IS_VALUE_ERROR (value))
if (ecma_is_value_true (is_array))
{
uint32_t array_length;
ecma_value_t to_len = ecma_op_object_get_length (obj_p, &array_length);
if (ECMA_IS_VALUE_ERROR (to_len))
{
ecma_collection_free (context.property_list_p);
return value;
return to_len;
}
/* 4.b.iii.5.c */
ecma_value_t item = ECMA_VALUE_UNDEFINED;
context.property_list_p = ecma_new_collection ();
/* 4.b.iii.5.d */
if (ecma_is_value_string (value))
{
ecma_ref_ecma_string (ecma_get_string_from_value (value));
item = value;
}
/* 4.b.iii.5.e */
else if (ecma_is_value_number (value))
{
ecma_string_t *number_str_p = ecma_op_to_string (value);
JERRY_ASSERT (number_str_p != NULL);
item = ecma_make_string_value (number_str_p);
}
/* 4.b.iii.5.f */
else if (ecma_is_value_object (value))
{
ecma_object_t *value_obj_p = ecma_get_object_from_value (value);
lit_magic_string_id_t class_id = ecma_object_get_class_name (value_obj_p);
uint32_t index = 0;
if (class_id == LIT_MAGIC_STRING_NUMBER_UL || class_id == LIT_MAGIC_STRING_STRING_UL)
/* 4.b.iii.5 */
while (index < array_length)
{
ecma_value_t value = ecma_op_object_get_by_uint32_index (obj_p, index);
if (ECMA_IS_VALUE_ERROR (value))
{
ecma_string_t *str_p = ecma_op_to_string (value);
ecma_collection_free (context.property_list_p);
return value;
}
if (JERRY_UNLIKELY (str_p == NULL))
/* 4.b.iii.5.c */
ecma_value_t item = ECMA_VALUE_UNDEFINED;
/* 4.b.iii.5.d */
if (ecma_is_value_string (value))
{
ecma_ref_ecma_string (ecma_get_string_from_value (value));
item = value;
}
/* 4.b.iii.5.e */
else if (ecma_is_value_number (value))
{
ecma_string_t *number_str_p = ecma_op_to_string (value);
JERRY_ASSERT (number_str_p != NULL);
item = ecma_make_string_value (number_str_p);
}
/* 4.b.iii.5.f */
else if (ecma_is_value_object (value))
{
ecma_object_t *value_obj_p = ecma_get_object_from_value (value);
lit_magic_string_id_t class_id = ecma_object_get_class_name (value_obj_p);
if (class_id == LIT_MAGIC_STRING_NUMBER_UL || class_id == LIT_MAGIC_STRING_STRING_UL)
{
ecma_collection_free (context.property_list_p);
ecma_free_value (value);
return ECMA_VALUE_ERROR;
ecma_string_t *str_p = ecma_op_to_string (value);
if (JERRY_UNLIKELY (str_p == NULL))
{
ecma_collection_free (context.property_list_p);
ecma_free_value (value);
return ECMA_VALUE_ERROR;
}
item = ecma_make_string_value (str_p);
}
item = ecma_make_string_value (str_p);
}
}
ecma_free_value (value);
ecma_free_value (value);
/* 4.b.iii.5.g */
if (!ecma_is_value_undefined (item))
{
JERRY_ASSERT (ecma_is_value_string (item));
ecma_string_t *string_p = ecma_get_string_from_value (item);
if (!ecma_has_string_value_in_collection (context.property_list_p, string_p))
/* 4.b.iii.5.g */
if (!ecma_is_value_undefined (item))
{
ecma_collection_push_back (context.property_list_p, item);
}
else
{
ecma_deref_ecma_string (string_p);
}
}
JERRY_ASSERT (ecma_is_value_string (item));
ecma_string_t *string_p = ecma_get_string_from_value (item);
index++;
if (!ecma_has_string_value_in_collection (context.property_list_p, string_p))
{
ecma_collection_push_back (context.property_list_p, item);
}
else
{
ecma_deref_ecma_string (string_p);
}
}
index++;
}
}
}
}

View File

@ -0,0 +1,19 @@
// 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.
function a() {
this[2] = { b : new Proxy(Function, {}) }
}
JSON.parse("[1, 2, []]", a);

View File

@ -0,0 +1,20 @@
// 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.
function a() {
this[2] = new Proxy(new function() { return new Array }, {})
return {}
}
JSON.parse("[1, 2, []]", a);