[njs] Making __proto__ accessor descriptor of Object mutable.
Dmitry Volyntsev
xeioex at nginx.com
Tue Apr 2 14:46:21 UTC 2019
details: https://hg.nginx.org/njs/rev/8d9585e9cc8b
branches:
changeset: 864:8d9585e9cc8b
user: Dmitry Volyntsev <xeioex at nginx.com>
date: Tue Apr 02 17:45:38 2019 +0300
description:
Making __proto__ accessor descriptor of Object mutable.
diffstat:
njs/njs_builtin.c | 2 +-
njs/njs_math.c | 2 +-
njs/njs_object.c | 73 +++++++++++++++++++++++++++++++++++++++++++----
njs/njs_object.h | 2 +-
njs/test/njs_unit_test.c | 14 ++++++++-
5 files changed, 82 insertions(+), 11 deletions(-)
diffs (167 lines):
diff -r 61f2616e21c7 -r 8d9585e9cc8b njs/njs_builtin.c
--- a/njs/njs_builtin.c Tue Apr 02 17:17:49 2019 +0300
+++ b/njs/njs_builtin.c Tue Apr 02 17:45:38 2019 +0300
@@ -414,7 +414,7 @@ njs_prototype_function(njs_vm_t *vm, njs
* Object(),
* Object.__proto__ -> Function_Prototype,
* Object_Prototype.__proto__ -> null,
- * the null value is handled by njs_object_prototype_get_proto(),
+ * the null value is handled by njs_object_prototype_proto(),
*
* Array(),
* Array.__proto__ -> Function_Prototype,
diff -r 61f2616e21c7 -r 8d9585e9cc8b njs/njs_math.c
--- a/njs/njs_math.c Tue Apr 02 17:17:49 2019 +0300
+++ b/njs/njs_math.c Tue Apr 02 17:45:38 2019 +0300
@@ -819,7 +819,7 @@ static const njs_object_prop_t njs_math
{
.type = NJS_PROPERTY_HANDLER,
.name = njs_string("__proto__"),
- .value = njs_prop_handler(njs_object_prototype_get_proto),
+ .value = njs_prop_handler(njs_object_prototype_proto),
},
{
diff -r 61f2616e21c7 -r 8d9585e9cc8b njs/njs_object.c
--- a/njs/njs_object.c Tue Apr 02 17:17:49 2019 +0300
+++ b/njs/njs_object.c Tue Apr 02 17:45:38 2019 +0300
@@ -1889,8 +1889,8 @@ njs_object_get_prototype_of(njs_vm_t *vm
value = njs_arg(args, nargs, 1);
if (njs_is_object(value)) {
- njs_object_prototype_get_proto(vm, (njs_value_t *) value, NULL,
- &vm->retval);
+ njs_object_prototype_proto(vm, (njs_value_t *) value, NULL,
+ &vm->retval);
return NXT_OK;
}
@@ -2393,13 +2393,71 @@ const njs_object_init_t njs_object_cons
};
+/*
+ * ES6, 9.1.2: [[SetPrototypeOf]].
+ */
+static nxt_bool_t
+njs_object_set_prototype_of(njs_vm_t *vm, njs_object_t *object,
+ const njs_value_t *value)
+{
+ const njs_object_t *proto;
+
+ proto = njs_is_object(value) ? value->data.u.object->__proto__
+ : NULL;
+
+ if (nxt_slow_path(object->__proto__ == proto)) {
+ return 1;
+ }
+
+ if (nxt_slow_path(proto == NULL)) {
+ object->__proto__ = NULL;
+ return 1;
+ }
+
+ do {
+ if (proto == object) {
+ return 0;
+ }
+
+ proto = proto->__proto__;
+
+ } while (proto != NULL);
+
+ object->__proto__ = value->data.u.object;
+
+ return 1;
+}
+
+
njs_ret_t
-njs_object_prototype_get_proto(njs_vm_t *vm, njs_value_t *value,
+njs_object_prototype_proto(njs_vm_t *vm, njs_value_t *value,
njs_value_t *setval, njs_value_t *retval)
{
- njs_object_t *proto;
-
- proto = value->data.u.object->__proto__;
+ nxt_bool_t ret;
+ njs_object_t *proto, *object;
+
+ if (!njs_is_object(value)) {
+ *retval = *value;
+ return NJS_OK;
+ }
+
+ object = value->data.u.object;
+
+ if (setval != NULL) {
+ if (njs_is_object(setval) || njs_is_null(setval)) {
+ ret = njs_object_set_prototype_of(vm, object, setval);
+ if (nxt_slow_path(!ret)) {
+ njs_type_error(vm, "Cyclic __proto__ value");
+ return NXT_ERROR;
+ }
+ }
+
+ *retval = njs_value_undefined;
+
+ return NJS_OK;
+ }
+
+ proto = object->__proto__;
if (nxt_fast_path(proto != NULL)) {
retval->data.u.object = proto;
@@ -2722,7 +2780,8 @@ static const njs_object_prop_t njs_obje
{
.type = NJS_PROPERTY_HANDLER,
.name = njs_string("__proto__"),
- .value = njs_prop_handler(njs_object_prototype_get_proto),
+ .value = njs_prop_handler(njs_object_prototype_proto),
+ .writable = 1,
},
{
diff -r 61f2616e21c7 -r 8d9585e9cc8b njs/njs_object.h
--- a/njs/njs_object.h Tue Apr 02 17:17:49 2019 +0300
+++ b/njs/njs_object.h Tue Apr 02 17:45:38 2019 +0300
@@ -106,7 +106,7 @@ njs_ret_t njs_object_prototype_create(nj
njs_value_t *setval, njs_value_t *retval);
njs_value_t *njs_property_prototype_create(njs_vm_t *vm, nxt_lvlhsh_t *hash,
njs_object_t *prototype);
-njs_ret_t njs_object_prototype_get_proto(njs_vm_t *vm, njs_value_t *value,
+njs_ret_t njs_object_prototype_proto(njs_vm_t *vm, njs_value_t *value,
njs_value_t *setval, njs_value_t *retval);
njs_value_t *njs_property_constructor_create(njs_vm_t *vm, nxt_lvlhsh_t *hash,
njs_value_t *constructor);
diff -r 61f2616e21c7 -r 8d9585e9cc8b njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c Tue Apr 02 17:17:49 2019 +0300
+++ b/njs/test/njs_unit_test.c Tue Apr 02 17:45:38 2019 +0300
@@ -7507,6 +7507,12 @@ static njs_unit_test_t njs_test[] =
{ nxt_string("Object.prototype.__proto__ === null"),
nxt_string("true") },
+ { nxt_string("Object.prototype.__proto__ = {}"),
+ nxt_string("TypeError: Cyclic __proto__ value") },
+
+ { nxt_string("var o = {}; var o2 = Object.create(o); o.__proto__ = o2"),
+ nxt_string("TypeError: Cyclic __proto__ value") },
+
{ nxt_string("Object.prototype.__proto__.f()"),
nxt_string("TypeError: cannot get property \"f\" of undefined") },
@@ -7529,7 +7535,13 @@ static njs_unit_test_t njs_test[] =
nxt_string("true") },
{ nxt_string("({}).__proto__ = 1"),
- nxt_string("TypeError: Cannot assign to read-only property \"__proto__\" of object") },
+ nxt_string("1") },
+
+ { nxt_string("({}).__proto__ = null"),
+ nxt_string("null") },
+
+ { nxt_string("({__proto__: []}) instanceof Array"),
+ nxt_string("true") },
{ nxt_string("({}).__proto__.constructor === Object"),
nxt_string("true") },
More information about the nginx-devel
mailing list