--- 20220818231006.zyhyj%stef...@sdaoden.eu: I just fixed two other bugs regarding $: ternary resolution which affect strange cases regarding precedence in whiteouts
$((0?I1=10:(1?I3:I2=12))) vs $((0?I1=10:(0?I3:I2=12))) as well as a missing variable-expansion prevention in a whiteout. (Let me allow to keep saying whiteout, please.) It bugs me. "Three line fix", so to say. Locally i added a couple of more tests, and i am now really out of ideas what other tests i could throw at the code. Sorry again for now waiting until i had an iteration. [.]I will send the small bugfix patch onto v2 tomorrow,[.] It is a bit larger than it could be because it adds a dedicated error constant, as well as renaming another one. shell/math.c | 5 +++-- shell/shexp-arith.h | 53 ++++++++++++++++++++++++++++++--------------- 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/shell/math.c b/shell/math.c index a20596089d..8388fdecad 100644 --- a/shell/math.c +++ b/shell/math.c @@ -214,7 +214,7 @@ static arith_t strto_arith_t(const char *nptr, char **endptr) #define CONCAT(S1,S2) su__CONCAT_1(S1, S2) # define su__CONCAT_1(S1,S2) su__CONCAT_2(S1, S2) # define su__CONCAT_2(S1,S2) S1 ## S2 -#define DBG(X) +#define DBGX(X) #define FALLTHRU #define N_(X) X #define NIL NULL @@ -299,8 +299,9 @@ arith(arith_state_t *math_state, const char *expr) a_X(ASSIGN_NO_VAR, "assignment without variable"); a_X(DIV_BY_ZERO, "division by zero"); a_X(EXP_INVALID, "invalid exponent"); - a_X(NO_OPERAND, "syntax error, expected operand"); + a_X(NO_OP, "syntax error, expected operand"); a_X(COND_NO_COLON, "syntax error, incomplete ?: condition"); + a_X(COND_PREC_INVALID, "?: condition, invalid precedence (1:v2:v3=3)"); a_X(NAME_LOOP, "recursive variable name reference"); a_X(OP_INVALID, "unknown operator"); } diff --git a/shell/shexp-arith.h b/shell/shexp-arith.h index f48ada1b46..fa44d4234d 100644 --- a/shell/shexp-arith.h +++ b/shell/shexp-arith.h @@ -47,8 +47,9 @@ enum a_shexp_arith_error{ a_SHEXP_ARITH_ERR_ASSIGN_NO_VAR, /* Assignment without variable */ a_SHEXP_ARITH_ERR_DIV_BY_ZERO, a_SHEXP_ARITH_ERR_EXP_INVALID, /* Invalid exponent */ - a_SHEXP_ARITH_ERR_NO_OPERAND, /* Expected an argument here */ + a_SHEXP_ARITH_ERR_NO_OP, /* Expected an argument here */ a_SHEXP_ARITH_ERR_COND_NO_COLON, /* Incomplete ?: condition */ + a_SHEXP_ARITH_ERR_COND_PREC_INVALID, /* 1 ? VAR1 : VAR2 = 3 */ a_SHEXP_ARITH_ERR_NAME_LOOP, /* Variable self-reference loop */ a_SHEXP_ARITH_ERR_OP_INVALID /* Unknown operator */ }; @@ -269,10 +270,10 @@ a_shexp_arith_eval( #endif ASSERT_NYD_EXEC(resp != NIL, - self.sac_error = a_SHEXP_ARITH_ERR_NO_OPERAND); - DBG( *resp = 0; ) + self.sac_error = a_SHEXP_ARITH_ERR_NO_OP); + DBGX( *resp = 0; ) ASSERT_NYD_EXEC(exp_len == 0 || exp_buf != NIL, - self.sac_error = a_SHEXP_ARITH_ERR_NO_OPERAND); + self.sac_error = a_SHEXP_ARITH_ERR_NO_OP); a_SHEXP_ARITH_IFS( self.sac_ifs_ws = ok_vlook(ifs_ws); ) self.sac_stack = &sas_stack; @@ -425,6 +426,7 @@ a_shexp__arith_eval(struct a_shexp_arith_ctx *self, ++sasp->sas_nums_top; lop = a_SHEXP_ARITH_OP_NUM; + a_SHEXP_ARITH_L((" + _arith_eval VAR <%s>\n", sasp->sas_nums_top[-1].sav_var)); continue; @@ -533,7 +535,7 @@ junapre: prec < a_SHEXP_ARITH_PREC_UNARY) || prec >= a_SHEXP_ARITH_PREC_SKY){ if(lop != a_SHEXP_ARITH_OP_NUM){ - self->sac_error = a_SHEXP_ARITH_ERR_NO_OPERAND; + self->sac_error = a_SHEXP_ARITH_ERR_NO_OP; goto jleave; } @@ -594,9 +596,11 @@ junapre: ASSERT(sasp->sas_nums_top > sasp->sas_nums); --sasp->sas_nums_top; - if((op & a_SHEXP_ARITH_OP_MASK) != a_SHEXP_ARITH_OP_ASSIGN && - sasp->sas_nums_top->sav_var != NIL){ - if(!a_shexp__arith_val_eval(self, sasp->sas_nums_top)) + if(sasp->sas_nums_top->sav_var != NIL){ + if(!(op & a_SHEXP_ARITH_OP_FLAG_WHITE_MASK) && + (op & a_SHEXP_ARITH_OP_MASK) != + a_SHEXP_ARITH_OP_ASSIGN && + !a_shexp__arith_val_eval(self, sasp->sas_nums_top)) goto jleave; sasp->sas_nums_top->sav_var = NIL; } @@ -669,17 +673,29 @@ junapre: } /* Is this a right-associative operation? */ else{ - boole doit=FAL0; + boole doit; + doit = FAL0; if(lprec < prec){ doit = TRU1; a_SHEXP_ARITH_L((" + _arith_eval DELAY PRECEDENCE\n")); }else if(lprec == prec && prec == a_SHEXP_ARITH_PREC_ASSIGN){ doit = TRU1; a_SHEXP_ARITH_L((" + _arith_eval DELAY RIGHT ASSOC\n")); - }else if(lop == a_SHEXP_ARITH_OP_COND){ - doit = TRU1; - a_SHEXP_ARITH_L((" + _arith_eval DELAY CONDITION\n")); + }else if(lprec == a_SHEXP_ARITH_PREC_COND){ + if(lop == a_SHEXP_ARITH_OP_COND){ + doit = TRU1; + a_SHEXP_ARITH_L((" + _arith_eval DELAY CONDITION\n")); + } + /* Without massive rewrite this is the location to detect + * in-whiteout precedence bugs as in + * $((0?I1=10:(1?I3:I2=12))) + * which would be parsed like (1?I3:I2)=12 without error + * (different to 0?I3:I2=12) otherwise */ + else if(op != a_SHEXP_ARITH_OP_COMMA){ + self->sac_error = a_SHEXP_ARITH_ERR_COND_PREC_INVALID; + goto jleave; + } } if(doit){ @@ -887,7 +903,7 @@ a_shexp__arith_op_apply(struct a_shexp_arith_ctx *self){ /* At least one argument is always needed */ if((nums_top = sasp->sas_nums_top) == sasp->sas_nums){ - self->sac_error = a_SHEXP_ARITH_ERR_NO_OPERAND; + self->sac_error = a_SHEXP_ARITH_ERR_NO_OP; goto jleave; } --nums_top; @@ -922,7 +938,9 @@ a_shexp__arith_op_apply(struct a_shexp_arith_ctx *self){ } goto jquick; }else if(op == a_SHEXP_ARITH_OP_COND_COLON){ + ASSERT(sasp->sas_ops_top > sasp->sas_ops); ASSERT(nums_top > sasp->sas_nums); + if(!ign){ /* Move the ternary value over to LHV where we find it as a result, * and ensure LHV's name is forgotten so not to evaluate it (for @@ -930,18 +948,17 @@ a_shexp__arith_op_apply(struct a_shexp_arith_ctx *self){ * outer group, because it still exists on number stack) */ nums_top[-1].sav_val = nums_top[0].sav_val; nums_top[-1].sav_var = NIL; - }else{ + }else val = nums_top[-1].sav_val; - /*nums_top[0].sav_var = NIL;*/ - } + sasp->sas_nums_top = nums_top; - ASSERT(sasp->sas_ops_top > sasp->sas_ops); if((sasp->sas_ops_top[-1] & a_SHEXP_ARITH_OP_MASK ) == a_SHEXP_ARITH_OP_COND_COLON){ --sasp->sas_ops_top; if(!a_shexp__arith_op_apply_colons(self)) goto jleave; + ASSERT(sasp->sas_nums_top > sasp->sas_nums); if(!ign) sasp->sas_nums_top[-1].sav_val = val; } @@ -950,7 +967,7 @@ a_shexp__arith_op_apply(struct a_shexp_arith_ctx *self){ s64 rval; if(nums_top == sasp->sas_nums){ - self->sac_error = a_SHEXP_ARITH_ERR_NO_OPERAND; + self->sac_error = a_SHEXP_ARITH_ERR_NO_OP; goto jleave; } sasp->sas_nums_top = nums_top--; -- 2.37.2 --steffen | |Der Kragenbaer, The moon bear, |der holt sich munter he cheerfully and one by one |einen nach dem anderen runter wa.ks himself off |(By Robert Gernhardt) _______________________________________________ busybox mailing list busybox@busybox.net http://lists.busybox.net/mailman/listinfo/busybox