mirror of
https://git.busybox.net/busybox
synced 2026-01-31 16:43:21 +00:00
shell/math: fix nested ?: and do not parse variables in not-taken branch
Fixes arith-ternary1.tests and arith-ternary_nested.tests function old new delta evaluate_string 1043 1101 +58 arith_apply 1087 1137 +50 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 108/0) Total: 108 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
a02450ff0b
commit
46dccd2ec0
7 changed files with 61 additions and 43 deletions
|
|
@ -1,5 +1,2 @@
|
|||
42:42
|
||||
a=0
|
||||
6:6
|
||||
a=b=+err+
|
||||
b=6
|
||||
|
|
|
|||
|
|
@ -3,10 +3,3 @@ a=0
|
|||
# The not-taken branch should not evaluate
|
||||
echo 42:$((1 ? 42 : (a+=2)))
|
||||
echo "a=$a"
|
||||
|
||||
a='b=+err+'
|
||||
b=5
|
||||
# The not-taken branch should not even parse variables
|
||||
echo 6:$((0 ? a : ++b))
|
||||
echo "a=$a"
|
||||
echo "b=$b"
|
||||
|
|
|
|||
|
|
@ -1 +1,3 @@
|
|||
5:5
|
||||
6:6
|
||||
a=b=+err+
|
||||
b=6
|
||||
|
|
|
|||
|
|
@ -1,2 +1,7 @@
|
|||
exec 2>&1
|
||||
echo 5:$((1?2?3?4?5:6:7:8:9))
|
||||
a='b=+err+'
|
||||
b=5
|
||||
# The not-taken branch should not parse variables
|
||||
echo 6:$((0 ? a : ++b))
|
||||
echo "a=$a"
|
||||
echo "b=$b"
|
||||
|
|
|
|||
1
shell/ash_test/ash-arith/arith-ternary_nested.right
Normal file
1
shell/ash_test/ash-arith/arith-ternary_nested.right
Normal file
|
|
@ -0,0 +1 @@
|
|||
5:5
|
||||
2
shell/ash_test/ash-arith/arith-ternary_nested.tests
Executable file
2
shell/ash_test/ash-arith/arith-ternary_nested.tests
Executable file
|
|
@ -0,0 +1,2 @@
|
|||
exec 2>&1
|
||||
echo 5:$((1?2?3?4?5:6:7:8:9))
|
||||
80
shell/math.c
80
shell/math.c
|
|
@ -331,6 +331,28 @@ arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_
|
|||
|
||||
top_of_stack = NUMPTR - 1;
|
||||
|
||||
if (op == TOK_CONDITIONAL_SEP) {
|
||||
/* "expr1 ? expr2 : expr3" operation */
|
||||
var_or_num_t *expr1 = &top_of_stack[-2];
|
||||
if (expr1 < numstack) {
|
||||
return "malformed ?: operator";
|
||||
}
|
||||
err = arith_lookup_val(math_state, expr1);
|
||||
if (err)
|
||||
return err;
|
||||
if (expr1->val != 0) /* select expr2 or expr3 */
|
||||
top_of_stack--;
|
||||
err = arith_lookup_val(math_state, top_of_stack);
|
||||
if (err)
|
||||
return err;
|
||||
NUMPTR = expr1 + 1;
|
||||
expr1->val = top_of_stack->val;
|
||||
expr1->var_name = NULL;
|
||||
return NULL;
|
||||
}
|
||||
if (op == TOK_CONDITIONAL) /* Example: $((a ? b)) */
|
||||
return "malformed ?: operator";
|
||||
|
||||
/* Resolve name to value, if needed */
|
||||
err = arith_lookup_val(math_state, top_of_stack);
|
||||
if (err)
|
||||
|
|
@ -350,25 +372,12 @@ arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_
|
|||
else if (op != TOK_UPLUS) {
|
||||
/* Binary operators */
|
||||
arith_t right_side_val;
|
||||
int bad_second_val;
|
||||
|
||||
/* Binary operators need two arguments */
|
||||
if (top_of_stack == numstack)
|
||||
goto syntax_err;
|
||||
/* ...and they pop one */
|
||||
NUMPTR = top_of_stack; /* this decrements NUMPTR */
|
||||
|
||||
bad_second_val = (top_of_stack->var_name == SECOND_VAL_VALID);
|
||||
if (op == TOK_CONDITIONAL) { /* ? operation */
|
||||
/* Make next if (...) protect against
|
||||
* $((expr1 ? expr2)) - that is, missing ": expr" */
|
||||
bad_second_val = !bad_second_val;
|
||||
}
|
||||
if (bad_second_val) {
|
||||
/* Protect against $((expr <not_?_op> expr1 : expr2)) */
|
||||
return "malformed ?: operator";
|
||||
}
|
||||
|
||||
top_of_stack--; /* now points to left side */
|
||||
|
||||
if (op != TOK_ASSIGN) {
|
||||
|
|
@ -380,19 +389,7 @@ arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_
|
|||
|
||||
right_side_val = rez;
|
||||
rez = top_of_stack->val;
|
||||
if (op == TOK_CONDITIONAL) /* ? operation */
|
||||
rez = (rez ? right_side_val : top_of_stack[1].second_val);
|
||||
else if (op == TOK_CONDITIONAL_SEP) { /* : operation */
|
||||
if (top_of_stack == numstack) {
|
||||
/* Protect against $((expr : expr)) */
|
||||
return "malformed ?: operator";
|
||||
}
|
||||
top_of_stack->val = rez;
|
||||
top_of_stack->second_val = right_side_val;
|
||||
top_of_stack->var_name = SECOND_VAL_VALID;
|
||||
return NULL;
|
||||
}
|
||||
else if (op == TOK_BOR || op == TOK_OR_ASSIGN)
|
||||
if (op == TOK_BOR || op == TOK_OR_ASSIGN)
|
||||
rez |= right_side_val;
|
||||
else if (op == TOK_OR)
|
||||
rez = right_side_val || rez;
|
||||
|
|
@ -833,7 +830,7 @@ evaluate_string(arith_state_t *math_state, const char *expr)
|
|||
lasttok = TOK_NUM;
|
||||
goto next;
|
||||
}
|
||||
/* Not (y), but ...x~y): fall through to evaluate x~y */
|
||||
/* Not (y), but ...x~y). Fall through to evaluate x~y */
|
||||
} else {
|
||||
operator prev_prec = PREC(prev_op);
|
||||
fix_assignment_prec(prec);
|
||||
|
|
@ -841,11 +838,17 @@ evaluate_string(arith_state_t *math_state, const char *expr)
|
|||
if (prev_prec < prec
|
||||
|| (prev_prec == prec && is_right_associative(prec))
|
||||
) {
|
||||
/* ...x~y@: push @ on opstack */
|
||||
opstackptr++; /* undo removal of ~ op */
|
||||
goto push_op;
|
||||
/* Unless a?b?c:d:... and we are at the second : */
|
||||
if (op != TOK_CONDITIONAL_SEP
|
||||
|| prev_op != TOK_CONDITIONAL_SEP
|
||||
) {
|
||||
/* ...x~y@: push @ on opstack */
|
||||
opstackptr++; /* undo removal of ~ op */
|
||||
goto push_op;
|
||||
}
|
||||
/* else: a?b?c:d:. Evaluate b?c:d, replace it on stack with result. Then repeat */
|
||||
}
|
||||
/* ...x~y@: evaluate x~y, replace it on stack with result. Then repeat */
|
||||
/* else: ...x~y@. Evaluate x~y, replace it on stack with result. Then repeat */
|
||||
}
|
||||
dbg("arith_apply(prev_op:%02x, numstack:%d)", prev_op, (int)(numstackptr - numstack));
|
||||
errmsg = arith_apply(math_state, prev_op, numstack, &numstackptr);
|
||||
|
|
@ -856,6 +859,21 @@ dbg(" numstack:%d val:%lld %lld %p", (int)(numstackptr - numstack),
|
|||
numstackptr[-1].var_name == SECOND_VAL_VALID ? numstackptr[-1].second_val : 0,
|
||||
numstackptr[-1].var_name
|
||||
);
|
||||
/* For ternary ?: we need to remove ? from opstack too, not just : */
|
||||
if (prev_op == TOK_CONDITIONAL_SEP) {
|
||||
// This is caught in arith_apply()
|
||||
//if (opstackptr == opstack) {
|
||||
// /* Example: $((2:3)) */
|
||||
// errmsg = "where is your ? in ?:";
|
||||
// goto err_with_custom_msg;
|
||||
//}
|
||||
opstackptr--;
|
||||
if (*opstackptr != TOK_CONDITIONAL) {
|
||||
/* Example: $((1,2:3)) */
|
||||
errmsg = "malformed ?: operator";
|
||||
goto err_with_custom_msg;
|
||||
}
|
||||
}
|
||||
} /* while (opstack not empty) */
|
||||
if (op == TOK_RPAREN) /* unpaired RPAREN? */
|
||||
goto err;
|
||||
|
|
|
|||
Loading…
Reference in a new issue