diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-json.c b/jerry-core/ecma/builtin-objects/ecma-builtin-json.c
index 982bab14a..21eb0da05 100644
--- a/jerry-core/ecma/builtin-objects/ecma-builtin-json.c
+++ b/jerry-core/ecma/builtin-objects/ecma-builtin-json.c
@@ -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.
*
diff --git a/tests/jerry/es.next/json-parse-proxy.js b/tests/jerry/es.next/json-parse-proxy.js
new file mode 100644
index 000000000..0a4413ea8
--- /dev/null
+++ b/tests/jerry/es.next/json-parse-proxy.js
@@ -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");
+}
diff --git a/tests/test262-esnext-excludelist.xml b/tests/test262-esnext-excludelist.xml
index 0d8070f15..3fc3ef330 100644
--- a/tests/test262-esnext-excludelist.xml
+++ b/tests/test262-esnext-excludelist.xml
@@ -979,11 +979,6 @@
-
-
-
-
-