From a4312d614f3b5d40f9d985d07dbfe03c9f1ca339 Mon Sep 17 00:00:00 2001 From: Szilagyi Adam Date: Thu, 30 Jul 2020 14:35:18 +0200 Subject: [PATCH] Fix prototype chain traversal in ecma_op_object_put_with_receiver (#4066) The ECMA_OBJECT_IS_PROXY(proto_p) check is necessary throughout the prototype chain not just at the beginning Fixes #4045 JerryScript-DCO-1.0-Signed-off-by: Adam Szilagyi aszilagy@inf.u-szeged.hu --- jerry-core/ecma/operations/ecma-objects.c | 66 +++++-------------- .../es.next/regression-test-issue-4045.js | 42 ++++++++++++ 2 files changed, 58 insertions(+), 50 deletions(-) create mode 100644 tests/jerry/es.next/regression-test-issue-4045.js diff --git a/jerry-core/ecma/operations/ecma-objects.c b/jerry-core/ecma/operations/ecma-objects.c index a8bac03cb..86fd4a4de 100644 --- a/jerry-core/ecma/operations/ecma-objects.c +++ b/jerry-core/ecma/operations/ecma-objects.c @@ -347,49 +347,6 @@ ecma_op_object_get_own_property (ecma_object_t *object_p, /**< the object */ return *property_p; } /* ecma_op_object_get_own_property */ -/** - * [[GetProperty]] ecma object's operation - * - * See also: - * ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8 - * - * @return pointer to a property - if it exists, - * NULL (i.e. ecma-undefined) - otherwise. - */ -static ecma_property_t -ecma_op_object_get_property (ecma_object_t *object_p, /**< the object */ - ecma_string_t *property_name_p, /**< property name */ - ecma_property_ref_t *property_ref_p, /**< property reference */ - uint32_t options) /**< option bits */ -{ - while (true) - { - ecma_property_t property = ecma_op_object_get_own_property (object_p, - property_name_p, - property_ref_p, - options); - - if (property != ECMA_PROPERTY_TYPE_NOT_FOUND && property != ECMA_PROPERTY_TYPE_NOT_FOUND_AND_STOP) - { - return property; - } - - if (property == ECMA_PROPERTY_TYPE_NOT_FOUND_AND_STOP) - { - break; - } - - if (object_p->u2.prototype_cp == JMEM_CP_NULL) - { - break; - } - - object_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, object_p->u2.prototype_cp); - } - - return ECMA_PROPERTY_TYPE_NOT_FOUND; -} /* ecma_op_object_get_property */ - /** * Generic [[HasProperty]] operation * @@ -1417,12 +1374,21 @@ ecma_op_object_put_with_receiver (ecma_object_t *object_p, /**< the object */ { bool create_new_property = true; - jmem_cpointer_t proto_cp = ecma_op_ordinary_object_get_prototype_of (object_p); + jmem_cpointer_t obj_cp; + ECMA_SET_NON_NULL_POINTER (obj_cp, object_p); + ecma_object_t *proto_p = object_p; - if (proto_cp != JMEM_CP_NULL) + while (true) { + obj_cp = ecma_op_ordinary_object_get_prototype_of (proto_p); + + if (obj_cp == JMEM_CP_NULL) + { + break; + } + ecma_property_ref_t property_ref = { NULL }; - ecma_object_t *proto_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, proto_cp); + proto_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, obj_cp); #if ENABLED (JERRY_BUILTIN_PROXY) if (ECMA_OBJECT_IS_PROXY (proto_p)) @@ -1435,10 +1401,10 @@ ecma_op_object_put_with_receiver (ecma_object_t *object_p, /**< the object */ } #endif /* ENABLED (JERRY_BUILTIN_PROXY) */ - ecma_property_t inherited_property = ecma_op_object_get_property (proto_p, - property_name_p, - &property_ref, - ECMA_PROPERTY_GET_NO_OPTIONS); + ecma_property_t inherited_property = ecma_op_object_get_own_property (proto_p, + property_name_p, + &property_ref, + ECMA_PROPERTY_GET_NO_OPTIONS); if (inherited_property != ECMA_PROPERTY_TYPE_NOT_FOUND) { diff --git a/tests/jerry/es.next/regression-test-issue-4045.js b/tests/jerry/es.next/regression-test-issue-4045.js new file mode 100644 index 000000000..ffaf00bbb --- /dev/null +++ b/tests/jerry/es.next/regression-test-issue-4045.js @@ -0,0 +1,42 @@ +// 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 a = new Proxy(eval, {}); +var b = { + y : 2 +}; +b.__proto__ = a; + +var f = []; +var c = []; +var d = new Date(); +d.__proto__ = b; +a.__proto__ = f; + +c.__proto__ = d; + + +var a1 = new String(); +a1.__proto__ = c; + +assert(a.__proto__ === f); +assert(b.__proto__.__proto__ === f); +assert(d.__proto__.__proto__ === a); +assert(c.__proto__.__proto__.__proto__ === a); +assert(a1.__proto__.__proto__.__proto__.__proto__ === a); + +var e = [] +a1.__proto__ = e; + +assert(a1.__proto__ === e);