]> git.kaiwu.me - njs.git/commitdiff
Fixed pre/post increment/decrement in assignment operations.
authorAlexander Borisov <alexander.borisov@nginx.com>
Thu, 23 Jul 2020 10:24:10 +0000 (13:24 +0300)
committerAlexander Borisov <alexander.borisov@nginx.com>
Thu, 23 Jul 2020 10:24:10 +0000 (13:24 +0300)
Previously, the compound assignment operations did not create temporary
index for increments/decrements in the generator. The result was that
the increment/decrement changed the value immediately in place, which
led to incorrect calculations.

The fix is to use a separate temporary index for increments/decrements in
assignment operations.

This closes #271 issue on GitHub.

src/njs_generator.c
src/njs_lexer.h
src/test/njs_unit_test.c

index 5174a08ef02cb83d61fc4fa2b4df9f41531129d6..31192718752c36d3571fba7f6dbfc7cff5fbc2c5 100644 (file)
@@ -1799,7 +1799,7 @@ njs_generate_operation_assignment(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
     njs_int_t              ret;
-    njs_index_t            index;
+    njs_index_t            index, src;
     njs_parser_node_t      *lvalue, *expr, *object, *property;
     njs_vmcode_move_t      *move;
     njs_vmcode_3addr_t     *code;
@@ -1876,6 +1876,34 @@ njs_generate_operation_assignment(njs_vm_t *vm, njs_generator_t *generator,
         return ret;
     }
 
+    if (njs_slow_path(njs_parser_has_side_effect(node->right))) {
+        /*
+         * Preserve object and property values stored in variables in a case
+         * if the variables can be changed by side effects in expression.
+         */
+        if (object->token_type == NJS_TOKEN_NAME) {
+            src = object->index;
+
+            index = njs_generate_node_temp_index_get(vm, generator, object);
+            if (njs_slow_path(index == NJS_INDEX_ERROR)) {
+                return NJS_ERROR;
+            }
+
+            njs_generate_code_move(generator, move, index, src, object);
+        }
+
+        if (property->token_type == NJS_TOKEN_NAME) {
+            src = property->index;
+
+            index = njs_generate_node_temp_index_get(vm, generator, property);
+            if (njs_slow_path(index == NJS_INDEX_ERROR)) {
+                return NJS_ERROR;
+            }
+
+            njs_generate_code_move(generator, move, index, src, property);
+        }
+    }
+
     index = njs_generate_node_temp_index_get(vm, generator, node);
     if (njs_slow_path(index == NJS_INDEX_ERROR)) {
         return NJS_ERROR;
index 6689dedaffa0f01702b3ddf7e3a82ac8bb19331f..9afc83cca6bf764dd2e9c39239ed5aecd3386294 100644 (file)
@@ -51,7 +51,12 @@ typedef enum {
     NJS_TOKEN_BITWISE_XOR_ASSIGNMENT,
     NJS_TOKEN_BITWISE_AND_ASSIGNMENT,
 
-#define NJS_TOKEN_LAST_ASSIGNMENT   NJS_TOKEN_BITWISE_AND_ASSIGNMENT
+    NJS_TOKEN_INCREMENT,
+    NJS_TOKEN_DECREMENT,
+    NJS_TOKEN_POST_INCREMENT,
+    NJS_TOKEN_POST_DECREMENT,
+
+#define NJS_TOKEN_LAST_ASSIGNMENT   NJS_TOKEN_POST_DECREMENT
 
     NJS_TOKEN_EQUAL,
     NJS_TOKEN_STRICT_EQUAL,
@@ -60,13 +65,9 @@ typedef enum {
 
     NJS_TOKEN_ADDITION,
     NJS_TOKEN_UNARY_PLUS,
-    NJS_TOKEN_INCREMENT,
-    NJS_TOKEN_POST_INCREMENT,
 
     NJS_TOKEN_SUBSTRACTION,
     NJS_TOKEN_UNARY_NEGATION,
-    NJS_TOKEN_DECREMENT,
-    NJS_TOKEN_POST_DECREMENT,
 
     NJS_TOKEN_MULTIPLICATION,
 
index 16864efe6c8e45c1c7a1fd697740450a3ac91fbf..30618bdf6706cdf8962f0e37279a17298a15aece 100644 (file)
@@ -2183,6 +2183,20 @@ static njs_unit_test_t  njs_test[] =
                  "var b = ++a; a +' '+ b"),
       njs_str("NaN NaN") },
 
+    { njs_str("var a = 0; a = a + ++a; a"),
+      njs_str("1") },
+
+    { njs_str("var a = 0; a += a + ++a; a"),
+      njs_str("1") },
+
+    { njs_str("var i = 0, arr = ['a', 'b'];"
+              "arr[i] = arr[i] + arr[++i]; arr"),
+      njs_str("ab,b") },
+
+    { njs_str("var i = 0, arr = ['a', 'b'];"
+              "arr[i] += arr[i] + arr[++i]; arr"),
+      njs_str("aab,b") },
+
     /* Post increment. */
 
     { njs_str("var a = 1;   a++"),
@@ -2265,6 +2279,20 @@ static njs_unit_test_t  njs_test[] =
                  "var b = a++; a +' '+ b"),
       njs_str("NaN NaN") },
 
+    { njs_str("var a = 0; a = a + a++; a"),
+      njs_str("0") },
+
+    { njs_str("var a = 0; a += a + a++; a"),
+      njs_str("0") },
+
+    { njs_str("var i = 1, arr = ['a', 'b'];"
+              "arr[i] = arr[i] + arr[i++]; arr"),
+      njs_str("a,bb") },
+
+    { njs_str("var i = 1, arr = ['a', 'b'];"
+              "arr[i] += arr[i] + arr[i++]; arr"),
+      njs_str("a,bbb") },
+
     /* Decrement. */
 
     { njs_str("var a = 1;   --a"),
@@ -2347,6 +2375,20 @@ static njs_unit_test_t  njs_test[] =
                  "var b = --a; a +' '+ b"),
       njs_str("NaN NaN") },
 
+    { njs_str("var a = 0; a = a + --a; a"),
+      njs_str("-1") },
+
+    { njs_str("var a = 0; a -= a + --a; a"),
+      njs_str("1") },
+
+    { njs_str("var i = 1, arr = ['a', 'b'];"
+              "arr[i] = arr[i] + arr[--i]; arr"),
+      njs_str("a,ba") },
+
+    { njs_str("var i = 1, arr = ['a', 'b'];"
+              "arr[i] += arr[i] + arr[--i]; arr"),
+      njs_str("a,bba") },
+
     /* Post decrement. */
 
     { njs_str("var a = 1;   a--"),
@@ -2429,6 +2471,20 @@ static njs_unit_test_t  njs_test[] =
                  "var b = a--; a +' '+ b"),
       njs_str("NaN NaN") },
 
+    { njs_str("var a = 0; a = a + a--; a"),
+      njs_str("0") },
+
+    { njs_str("var a = 0; a += a + a--; a"),
+      njs_str("0") },
+
+    { njs_str("var i = 1, arr = ['a', 'b'];"
+              "arr[i] = arr[i] + arr[i--]; arr"),
+      njs_str("a,bb") },
+
+    { njs_str("var i = 1, arr = ['a', 'b'];"
+              "arr[i] += arr[i] + arr[i--]; arr"),
+      njs_str("a,bbb") },
+
     /**/
 
     { njs_str("var a, b; a = 2; b = ++a + ++a; a + ' ' + b"),