[njs] Fixed pre/post increment/decrement in assignment operations.
Alexander Borisov
alexander.borisov at nginx.com
Fri Jul 24 10:04:13 UTC 2020
details: https://hg.nginx.org/njs/rev/78f0887e5aa6
branches:
changeset: 1478:78f0887e5aa6
user: Alexander Borisov <alexander.borisov at nginx.com>
date: Thu Jul 23 13:24:10 2020 +0300
description:
Fixed pre/post increment/decrement in assignment operations.
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.
diffstat:
src/njs_generator.c | 30 ++++++++++++++++++++++++-
src/njs_lexer.h | 11 +++++----
src/test/njs_unit_test.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 91 insertions(+), 6 deletions(-)
diffs (165 lines):
diff -r 7f5c5a425d03 -r 78f0887e5aa6 src/njs_generator.c
--- a/src/njs_generator.c Wed Jul 22 15:21:15 2020 +0300
+++ b/src/njs_generator.c Thu Jul 23 13:24:10 2020 +0300
@@ -1799,7 +1799,7 @@ njs_generate_operation_assignment(njs_vm
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
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;
diff -r 7f5c5a425d03 -r 78f0887e5aa6 src/njs_lexer.h
--- a/src/njs_lexer.h Wed Jul 22 15:21:15 2020 +0300
+++ b/src/njs_lexer.h Thu Jul 23 13:24:10 2020 +0300
@@ -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,
diff -r 7f5c5a425d03 -r 78f0887e5aa6 src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c Wed Jul 22 15:21:15 2020 +0300
+++ b/src/test/njs_unit_test.c Thu Jul 23 13:24:10 2020 +0300
@@ -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"),
More information about the nginx-devel
mailing list