]> git.kaiwu.me - njs.git/commitdiff
Fixed array length property handler.
authorValentin Bartenev <vbart@nginx.com>
Thu, 23 May 2019 12:05:51 +0000 (15:05 +0300)
committerValentin Bartenev <vbart@nginx.com>
Thu, 23 May 2019 12:05:51 +0000 (15:05 +0300)
Previously it might change the length of prototype arrays.

njs/njs_array.c
njs/njs_vm.c
njs/njs_vm.h
njs/test/njs_unit_test.c

index efd055868216f71a39c2140f01e55f76300697d7..2f13437bc0f3ee23a79620b107ba2a06a16f38f8 100644 (file)
@@ -434,57 +434,65 @@ njs_array_length(njs_vm_t *vm, njs_value_t *value, njs_value_t *setval,
 
     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);
+        array = (njs_array_t *) proto;
 
-    if (nxt_slow_path(proto == NULL)) {
-        njs_internal_error(vm, "no array in proto chain");
-        return NJS_ERROR;
+        njs_value_number_set(retval, array->length);
+        return NJS_OK;
     }
 
-    array = (njs_array_t *) proto;
-
-    if (setval != NULL) {
-        if (!njs_is_number(setval)) {
-            njs_range_error(vm, "Invalid array length");
-            return NJS_ERROR;
-        }
+    if (proto->type != NJS_ARRAY) {
+        return NJS_DECLINED;
+    }
 
-        num = setval->data.u.number;
-        length = (uint32_t) num;
+    if (!njs_is_number(setval)) {
+        njs_range_error(vm, "Invalid array length");
+        return NJS_ERROR;
+    }
 
-        if ((double) length != num) {
-            njs_range_error(vm, "Invalid array length");
-            return NJS_ERROR;
-        }
+    num = setval->data.u.number;
+    length = (uint32_t) num;
 
-        size = (int64_t) length - array->length;
+    if ((double) length != num) {
+        njs_range_error(vm, "Invalid array length");
+        return NJS_ERROR;
+    }
 
-        if (size > 0) {
-            ret = njs_array_expand(vm, array, 0, size);
-            if (nxt_slow_path(ret != NXT_OK)) {
-                return NJS_ERROR;
-            }
+    array = (njs_array_t *) proto;
 
-            val = &array->start[array->length];
+    size = (int64_t) length - array->length;
 
-            do {
-                njs_set_invalid(val);
-                val++;
-                size--;
-            } while (size != 0);
+    if (size > 0) {
+        ret = njs_array_expand(vm, array, 0, size);
+        if (nxt_slow_path(ret != NXT_OK)) {
+            return NJS_ERROR;
         }
 
-        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;
 }
 
index c13f5c74631cd9e35c2d81f3e60f8263226a7181..f6f2e3e7654034680b5dd15f14cae537a79b88b1 100644 (file)
@@ -694,11 +694,17 @@ njs_vmcode_property_set(njs_vm_t *vm, njs_value_t *object,
         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) {
index 1f14fa9c8a5feda22753644d9eeef0f34d79bed9..41f2b5c34f624257c8274bd657a0f424af7a4497 100644 (file)
@@ -147,6 +147,11 @@ typedef struct njs_generator_s        njs_generator_t;
  * 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);
index a3dc530cd1ac2af1db9b7bd39c70a80d09ca7561..ecb873db2da82de8b4bd9322144d4f4fca4c52d1 100644 (file)
@@ -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]"),