Handle errors in JSON.parse triggered by Proxies (#4134)
Fixes: #4130 JerryScript-DCO-1.0-Signed-off-by: Peter Gal pgal.usz@partner.samsung.com
This commit is contained in:
@@ -601,6 +601,11 @@ ecma_builtin_json_parse_value (ecma_json_token_t *token_p) /**< token argument *
|
||||
}
|
||||
} /* ecma_builtin_json_parse_value */
|
||||
|
||||
static ecma_value_t
|
||||
ecma_builtin_json_internalize_process_property (ecma_object_t *reviver_p,
|
||||
ecma_object_t *object_p,
|
||||
ecma_string_t *prop_name);
|
||||
|
||||
/**
|
||||
* Abstract operation InternalizeJSONProperty
|
||||
*
|
||||
@@ -666,30 +671,17 @@ ecma_builtin_json_internalize_property (ecma_object_t *reviver_p, /**< reviver f
|
||||
for (ecma_length_t i = 0; i < length; i++)
|
||||
{
|
||||
ecma_string_t *prop_index = ecma_new_ecma_string_from_length (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 (object_p, prop_index, 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_value_t result = ecma_builtin_json_internalize_process_property (reviver_p, object_p, prop_index);
|
||||
|
||||
ecma_deref_ecma_string (prop_index);
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (result))
|
||||
{
|
||||
ecma_deref_object (object_p);
|
||||
return result;
|
||||
}
|
||||
|
||||
JERRY_ASSERT (result == ECMA_VALUE_TRUE);
|
||||
}
|
||||
}
|
||||
/* 3.d */
|
||||
@@ -697,8 +689,15 @@ ecma_builtin_json_internalize_property (ecma_object_t *reviver_p, /**< reviver f
|
||||
{
|
||||
ecma_collection_t *props_p = ecma_op_object_get_enumerable_property_names (object_p,
|
||||
ECMA_ENUMERABLE_PROPERTY_KEYS);
|
||||
|
||||
#if ENABLED (JERRY_ESNEXT)
|
||||
if (JERRY_UNLIKELY (props_p == NULL))
|
||||
{
|
||||
ecma_deref_object (object_p);
|
||||
return ECMA_VALUE_ERROR;
|
||||
}
|
||||
#else /* !ENABLED (JERRY_ESNEXT) */
|
||||
JERRY_ASSERT (props_p != NULL);
|
||||
#endif /* ENABLED (JERRY_ESNEXT) */
|
||||
|
||||
ecma_value_t *buffer_p = props_p->buffer_p;
|
||||
|
||||
@@ -706,35 +705,16 @@ ecma_builtin_json_internalize_property (ecma_object_t *reviver_p, /**< reviver f
|
||||
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]);
|
||||
ecma_value_t result = ecma_builtin_json_internalize_process_property (reviver_p, object_p, property_name_p);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
JERRY_ASSERT (result == ECMA_VALUE_TRUE);
|
||||
}
|
||||
|
||||
ecma_collection_free (props_p);
|
||||
@@ -754,6 +734,66 @@ ecma_builtin_json_internalize_property (ecma_object_t *reviver_p, /**< reviver f
|
||||
return ret_value;
|
||||
} /* ecma_builtin_json_internalize_property */
|
||||
|
||||
/**
|
||||
* Part of the InternalizeJSONProperty abstract method.
|
||||
*
|
||||
* See also:
|
||||
* ECMA-262 v5, 15.12.2
|
||||
* ECMA-262 v11, 24.5.1.1 in step 2
|
||||
*
|
||||
* @return ECMA_VALUE_TRUE - if no error occured.
|
||||
* error if one of the operation failed.
|
||||
*/
|
||||
static
|
||||
ecma_value_t ecma_builtin_json_internalize_process_property (ecma_object_t *reviver_p, /**< reviver function */
|
||||
ecma_object_t *object_p, /**< holder object */
|
||||
ecma_string_t *prop_name) /**< property name */
|
||||
{
|
||||
/* ES11: 2.b.iii.1 / 2.c.ii.1 */
|
||||
ecma_value_t new_element = ecma_builtin_json_internalize_property (reviver_p, object_p, prop_name);
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (new_element))
|
||||
{
|
||||
return new_element;
|
||||
}
|
||||
|
||||
/* ES11: 2.b.iii.2 / 2.c.ii.2 */
|
||||
if (ecma_is_value_undefined (new_element))
|
||||
{
|
||||
/* ES11: 2.b.iii.2.a / 2.c.ii.2.a */
|
||||
ecma_value_t delete_val = ecma_op_object_delete (object_p, prop_name, false);
|
||||
|
||||
#if ENABLED (JERRY_ESNEXT)
|
||||
if (ECMA_IS_VALUE_ERROR (delete_val))
|
||||
{
|
||||
return delete_val;
|
||||
}
|
||||
#endif /* ENABLED (JERRY_ESNEXT) */
|
||||
|
||||
JERRY_ASSERT (ecma_is_value_boolean (delete_val));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* ES11: 2.b.iii.3.a / 2.c.ii.3.a */
|
||||
ecma_value_t def_value = ecma_builtin_helper_def_prop (object_p,
|
||||
prop_name,
|
||||
new_element,
|
||||
ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE);
|
||||
ecma_free_value (new_element);
|
||||
|
||||
#if ENABLED (JERRY_ESNEXT)
|
||||
if (ECMA_IS_VALUE_ERROR (def_value))
|
||||
{
|
||||
return def_value;
|
||||
}
|
||||
#endif /* ENABLED (JERRY_ESNEXT) */
|
||||
|
||||
JERRY_ASSERT (ecma_is_value_boolean (def_value));
|
||||
}
|
||||
|
||||
return ECMA_VALUE_TRUE;
|
||||
} /* ecma_builtin_json_internalize_process_property */
|
||||
|
||||
/**
|
||||
* Function to set a string token from the given arguments, fills its fields and advances the string pointer.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
// 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.
|
||||
|
||||
/* Test JSON parse [[delete]] with Array */
|
||||
var badDeleteArray = new Proxy([0], {
|
||||
deleteProperty: function() {
|
||||
throw "My Super Error A";
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
JSON.parse('[0,0]', function() { this[1] = badDeleteArray; });
|
||||
} catch (ex) {
|
||||
assert(ex === "My Super Error A");
|
||||
}
|
||||
|
||||
/* Test JSON parse [[delete]] with Objects */
|
||||
var badDeleteObj = new Proxy([0], {
|
||||
deleteProperty: function() {
|
||||
throw "My Super Error B";
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
JSON.parse('[0,0]', function() { this[1] = badDeleteObj; });
|
||||
} catch (ex) {
|
||||
assert(ex === "My Super Error B");
|
||||
}
|
||||
|
||||
/* Test JSON parse property define with Array */
|
||||
var badDefineArray = new Proxy([null], {
|
||||
defineProperty: function(_, name) {
|
||||
throw "My Super Error C";
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
JSON.parse('["first", null]', function(_, value) {
|
||||
if (value === 'first') {
|
||||
this[1] = badDefineArray;
|
||||
}
|
||||
return value;
|
||||
});
|
||||
} catch (ex) {
|
||||
assert(ex === "My Super Error C");
|
||||
}
|
||||
|
||||
/* Test JSON parse property define with Object */
|
||||
var badDefineObj = new Proxy({0: null}, {
|
||||
defineProperty: function(_, name) {
|
||||
throw "My Super Error D";
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
JSON.parse('["first", null]', function(_, value) {
|
||||
if (value === 'first') {
|
||||
this[1] = badDefineObj;
|
||||
}
|
||||
return value;
|
||||
});
|
||||
} catch (ex) {
|
||||
assert(ex === "My Super Error D");
|
||||
}
|
||||
|
||||
/* Test JSON parse keys call */
|
||||
var badKeys = new Proxy({}, {
|
||||
ownKeys: function() {
|
||||
throw "My Super Error E";
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
JSON.parse('[0,0]', function() { this[1] = badKeys; });
|
||||
} catch (ex) {
|
||||
assert(ex === "My Super Error E");
|
||||
}
|
||||
@@ -979,11 +979,6 @@
|
||||
<test id="built-ins/GeneratorFunction/proto-from-ctor-realm-prototype.js"><reason></reason></test>
|
||||
<test id="built-ins/GeneratorFunction/proto-from-ctor-realm.js"><reason></reason></test>
|
||||
<test id="built-ins/GeneratorPrototype/return/from-state-completed.js"><reason></reason></test>
|
||||
<test id="built-ins/JSON/parse/reviver-array-define-prop-err.js"><reason></reason></test>
|
||||
<test id="built-ins/JSON/parse/reviver-array-delete-err.js"><reason></reason></test>
|
||||
<test id="built-ins/JSON/parse/reviver-object-define-prop-err.js"><reason></reason></test>
|
||||
<test id="built-ins/JSON/parse/reviver-object-delete-err.js"><reason></reason></test>
|
||||
<test id="built-ins/JSON/parse/reviver-object-own-keys-err.js"><reason></reason></test>
|
||||
<test id="built-ins/JSON/stringify/replacer-array-proxy-revoked-realm.js"><reason></reason></test>
|
||||
<test id="built-ins/JSON/stringify/value-bigint-cross-realm.js"><reason></reason></test>
|
||||
<test id="built-ins/JSON/stringify/value-bigint-order.js"><reason></reason></test>
|
||||
|
||||
Reference in New Issue
Block a user