[njs] Fixed array length property handler.

Valentin Bartenev vbart at nginx.com
Thu May 23 12:54:48 UTC 2019


details:   https://hg.nginx.org/njs/rev/fd0918b6dd56
branches:  
changeset: 981:fd0918b6dd56
user:      Valentin Bartenev <vbart at nginx.com>
date:      Thu May 23 15:05:51 2019 +0300
description:
Fixed array length property handler.

Previously it might change the length of prototype arrays.

diffstat:

 njs/njs_array.c          |  86 ++++++++++++++++++++++++++---------------------
 njs/njs_vm.c             |  12 +++++-
 njs/njs_vm.h             |   5 ++
 njs/test/njs_unit_test.c |   4 ++
 4 files changed, 65 insertions(+), 42 deletions(-)

diffs (161 lines):

diff -r f7eedb8257eb -r fd0918b6dd56 njs/njs_array.c
--- a/njs/njs_array.c	Thu May 23 15:05:51 2019 +0300
+++ b/njs/njs_array.c	Thu May 23 15:05:51 2019 +0300
@@ -434,57 +434,65 @@ njs_array_length(njs_vm_t *vm, njs_value
 
     proto = value->data.u.object;
 
-    do {
-        if (nxt_fast_path(proto->type == NJS_ARRAY)) {
-            break;
+    if (setval == NULL) {
+        do {
+            if (nxt_fast_path(proto->type == NJS_ARRAY)) {
+                break;
+            }
+
+            proto = proto->__proto__;
+        } while (proto != NULL);
+
+        if (nxt_slow_path(proto == NULL)) {
+            njs_internal_error(vm, "no array in proto chain");
+            return NJS_ERROR;
         }
 
-        proto = proto->__proto__;
-    } while (proto != NULL);
-
-    if (nxt_slow_path(proto == NULL)) {
-        njs_internal_error(vm, "no array in proto chain");
+        array = (njs_array_t *) proto;
+
+        njs_value_number_set(retval, array->length);
+        return NJS_OK;
+    }
+
+    if (proto->type != NJS_ARRAY) {
+        return NJS_DECLINED;
+    }
+
+    if (!njs_is_number(setval)) {
+        njs_range_error(vm, "Invalid array length");
+        return NJS_ERROR;
+    }
+
+    num = setval->data.u.number;
+    length = (uint32_t) num;
+
+    if ((double) length != num) {
+        njs_range_error(vm, "Invalid array length");
         return NJS_ERROR;
     }
 
     array = (njs_array_t *) proto;
 
-    if (setval != NULL) {
-        if (!njs_is_number(setval)) {
-            njs_range_error(vm, "Invalid array length");
-            return NJS_ERROR;
-        }
-
-        num = setval->data.u.number;
-        length = (uint32_t) num;
-
-        if ((double) length != num) {
-            njs_range_error(vm, "Invalid array length");
+    size = (int64_t) length - array->length;
+
+    if (size > 0) {
+        ret = njs_array_expand(vm, array, 0, size);
+        if (nxt_slow_path(ret != NXT_OK)) {
             return NJS_ERROR;
         }
 
-        size = (int64_t) length - array->length;
-
-        if (size > 0) {
-            ret = njs_array_expand(vm, array, 0, size);
-            if (nxt_slow_path(ret != NXT_OK)) {
-                return NJS_ERROR;
-            }
-
-            val = &array->start[array->length];
-
-            do {
-                njs_set_invalid(val);
-                val++;
-                size--;
-            } while (size != 0);
-        }
-
-        array->length = length;
+        val = &array->start[array->length];
+
+        do {
+            njs_set_invalid(val);
+            val++;
+            size--;
+        } while (size != 0);
     }
 
-    njs_value_number_set(retval, array->length);
-
+    array->length = length;
+
+    njs_value_number_set(retval, length);
     return NJS_OK;
 }
 
diff -r f7eedb8257eb -r fd0918b6dd56 njs/njs_vm.c
--- a/njs/njs_vm.c	Thu May 23 15:05:51 2019 +0300
+++ b/njs/njs_vm.c	Thu May 23 15:05:51 2019 +0300
@@ -694,11 +694,17 @@ njs_vmcode_property_set(njs_vm_t *vm, nj
         if (prop->type == NJS_PROPERTY_HANDLER) {
             ret = prop->value.data.u.prop_handler(vm, object, value,
                                                   &vm->retval);
-            if (nxt_slow_path(ret != NXT_OK)) {
+
+            switch (ret) {
+            case NXT_OK:
+                return sizeof(njs_vmcode_prop_set_t);
+
+            case NXT_DECLINED:
+                break;
+
+            default:
                 return ret;
             }
-
-            return sizeof(njs_vmcode_prop_set_t);
         }
 
         if (pq.own) {
diff -r f7eedb8257eb -r fd0918b6dd56 njs/njs_vm.h
--- a/njs/njs_vm.h	Thu May 23 15:05:51 2019 +0300
+++ b/njs/njs_vm.h	Thu May 23 15:05:51 2019 +0300
@@ -147,6 +147,11 @@ typedef struct njs_generator_s        nj
  * njs_prop_handler_t operates as a property getter and/or setter.
  * The handler receives NULL setval if it is invoked in GET context and
  * non-null otherwise.
+ *
+ * njs_prop_handler_t is expected to return:
+ *   NXT_OK - handler executed successfully;
+ *   NXT_ERROR - some error, vm->retval contains appropriate exception;
+ *   NXT_DECLINED - handler was applied to inappropriate object.
  */
 typedef njs_ret_t (*njs_prop_handler_t) (njs_vm_t *vm, njs_value_t *value,
     njs_value_t *setval, njs_value_t *retval);
diff -r f7eedb8257eb -r fd0918b6dd56 njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c	Thu May 23 15:05:51 2019 +0300
+++ b/njs/test/njs_unit_test.c	Thu May 23 15:05:51 2019 +0300
@@ -8405,6 +8405,10 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("Array.prototype.length = 3, Array.prototype"),
       nxt_string(",,") },
 
+    { nxt_string("var o = Object.create(Array.prototype); o.length = 3;"
+                 "[Array.prototype, Array.prototype.length, o.length]"),
+      nxt_string(",0,3") },
+
     { nxt_string("var o = Object.create(Array.prototype);"
                  "Object.defineProperty(o, 'length', {value: 3});"
                  "[Array.prototype, Array.prototype.length, o.length]"),


More information about the nginx-devel mailing list