From 3df885abe340c5feaed212536139ee24d60e40a2 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 14 Jun 2023 11:33:59 +0200 Subject: shell/math: fix the order of variable resolution in binops function old new delta arith_apply 1134 1143 +9 Signed-off-by: Denys Vlasenko --- .../hush-arith/arith-assign-in-varexp.right | 3 +++ .../hush-arith/arith-assign-in-varexp.tests | 8 +++++++ shell/hush_test/hush-arith/arith-comma1.right | 3 +++ shell/hush_test/hush-arith/arith-comma1.tests | 6 +++++ shell/hush_test/hush-arith/arith-ternary2.right | 3 +++ shell/hush_test/hush-arith/arith-ternary2.tests | 7 ++++++ .../hush-arith/arith-ternary_nested.right | 1 + .../hush-arith/arith-ternary_nested.tests | 2 ++ shell/math.c | 27 ++++++++++++---------- 9 files changed, 48 insertions(+), 12 deletions(-) create mode 100644 shell/hush_test/hush-arith/arith-assign-in-varexp.right create mode 100755 shell/hush_test/hush-arith/arith-assign-in-varexp.tests create mode 100644 shell/hush_test/hush-arith/arith-comma1.right create mode 100755 shell/hush_test/hush-arith/arith-comma1.tests create mode 100644 shell/hush_test/hush-arith/arith-ternary2.right create mode 100755 shell/hush_test/hush-arith/arith-ternary2.tests create mode 100644 shell/hush_test/hush-arith/arith-ternary_nested.right create mode 100755 shell/hush_test/hush-arith/arith-ternary_nested.tests (limited to 'shell') diff --git a/shell/hush_test/hush-arith/arith-assign-in-varexp.right b/shell/hush_test/hush-arith/arith-assign-in-varexp.right new file mode 100644 index 0000000..06ac80a --- /dev/null +++ b/shell/hush_test/hush-arith/arith-assign-in-varexp.right @@ -0,0 +1,3 @@ +20:20 +a=b=10 +b=10 diff --git a/shell/hush_test/hush-arith/arith-assign-in-varexp.tests b/shell/hush_test/hush-arith/arith-assign-in-varexp.tests new file mode 100755 index 0000000..920aaa7 --- /dev/null +++ b/shell/hush_test/hush-arith/arith-assign-in-varexp.tests @@ -0,0 +1,8 @@ +exec 2>&1 +a='b=10' +b=3 +# The variables should evaluate left-to-right, +# thus b is set to 10 _before_ addition +echo 20:$((a + b)) +echo "a=$a" +echo "b=$b" diff --git a/shell/hush_test/hush-arith/arith-comma1.right b/shell/hush_test/hush-arith/arith-comma1.right new file mode 100644 index 0000000..be1264c --- /dev/null +++ b/shell/hush_test/hush-arith/arith-comma1.right @@ -0,0 +1,3 @@ +10:10 +a=b=10 +b=10 diff --git a/shell/hush_test/hush-arith/arith-comma1.tests b/shell/hush_test/hush-arith/arith-comma1.tests new file mode 100755 index 0000000..f863043 --- /dev/null +++ b/shell/hush_test/hush-arith/arith-comma1.tests @@ -0,0 +1,6 @@ +exec 2>&1 +a='b=10' +b=3 +echo 10:$((a,b)) +echo "a=$a" +echo "b=$b" diff --git a/shell/hush_test/hush-arith/arith-ternary2.right b/shell/hush_test/hush-arith/arith-ternary2.right new file mode 100644 index 0000000..a549b1b --- /dev/null +++ b/shell/hush_test/hush-arith/arith-ternary2.right @@ -0,0 +1,3 @@ +6:6 +a=b=+err+ +b=6 diff --git a/shell/hush_test/hush-arith/arith-ternary2.tests b/shell/hush_test/hush-arith/arith-ternary2.tests new file mode 100755 index 0000000..cb31639 --- /dev/null +++ b/shell/hush_test/hush-arith/arith-ternary2.tests @@ -0,0 +1,7 @@ +exec 2>&1 +a='b=+err+' +b=5 +# The not-taken branch should not parse variables +echo 6:$((0 ? a : ++b)) +echo "a=$a" +echo "b=$b" diff --git a/shell/hush_test/hush-arith/arith-ternary_nested.right b/shell/hush_test/hush-arith/arith-ternary_nested.right new file mode 100644 index 0000000..aa54bd9 --- /dev/null +++ b/shell/hush_test/hush-arith/arith-ternary_nested.right @@ -0,0 +1 @@ +5:5 diff --git a/shell/hush_test/hush-arith/arith-ternary_nested.tests b/shell/hush_test/hush-arith/arith-ternary_nested.tests new file mode 100755 index 0000000..eefc8e7 --- /dev/null +++ b/shell/hush_test/hush-arith/arith-ternary_nested.tests @@ -0,0 +1,2 @@ +exec 2>&1 +echo 5:$((1?2?3?4?5:6:7:8:9)) diff --git a/shell/math.c b/shell/math.c index fa22bc4..077aba8 100644 --- a/shell/math.c +++ b/shell/math.c @@ -340,7 +340,20 @@ arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_ if (op == TOK_CONDITIONAL) /* Example: $((a ? b)) */ return "malformed ?: operator"; - /* Resolve name to value, if needed */ + if (PREC(op) < UNARYPREC) { + /* In binops a ~ b, variables are resolved left-to-right, + * resolve top_of_stack[-1] _before_ resolving top_of_stack[0] + */ + if (top_of_stack == numstack) /* need two arguments */ + goto syntax_err; + /* Unless it is =, resolve top_of_stack[-1] name to value */ + if (op != TOK_ASSIGN) { + err = arith_lookup_val(math_state, top_of_stack - 1); + if (err) + return err; + } + } + /* Resolve top_of_stack[0] name to value */ err = arith_lookup_val(math_state, top_of_stack); if (err) return err; @@ -360,20 +373,10 @@ arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_ /* Binary operators */ arith_t right_side_val; - /* Binary operators need two arguments */ - if (top_of_stack == numstack) - goto syntax_err; - /* ...and they pop one */ + /* Pop numstack */ NUMPTR = top_of_stack; /* this decrements NUMPTR */ top_of_stack--; /* now points to left side */ - if (op != TOK_ASSIGN) { - /* Resolve left side value (unless the op is '=') */ - err = arith_lookup_val(math_state, top_of_stack); - if (err) - return err; - } - right_side_val = rez; rez = top_of_stack->val; if (op == TOK_BOR || op == TOK_OR_ASSIGN) -- cgit v1.1