comparison src/eval.c @ 23679:e8c379b20765 v8.2.2381

patch 8.2.2381: Vim9: divide by zero does not abort expression execution Commit: https://github.com/vim/vim/commit/c5f59fab23820454f060562927ddc1397f9d479a Author: Bram Moolenaar <Bram@vim.org> Date: Thu Jan 21 12:34:14 2021 +0100 patch 8.2.2381: Vim9: divide by zero does not abort expression execution Problem: Vim9: divide by zero does not abort expression execution. Solution: Use a "failed" flag. (issue https://github.com/vim/vim/issues/7704)
author Bram Moolenaar <Bram@vim.org>
date Thu, 21 Jan 2021 12:45:05 +0100
parents 6d35bc0f161e
children a0c4d04a58c4
comparison
equal deleted inserted replaced
23678:8548a27908be 23679:e8c379b20765
55 static int free_unref_items(int copyID); 55 static int free_unref_items(int copyID);
56 static char_u *make_expanded_name(char_u *in_start, char_u *expr_start, char_u *expr_end, char_u *in_end); 56 static char_u *make_expanded_name(char_u *in_start, char_u *expr_start, char_u *expr_end, char_u *in_end);
57 57
58 /* 58 /*
59 * Return "n1" divided by "n2", taking care of dividing by zero. 59 * Return "n1" divided by "n2", taking care of dividing by zero.
60 * If "failed" is not NULL set it to TRUE when dividing by zero fails.
60 */ 61 */
61 varnumber_T 62 varnumber_T
62 num_divide(varnumber_T n1, varnumber_T n2) 63 num_divide(varnumber_T n1, varnumber_T n2, int *failed)
63 { 64 {
64 varnumber_T result; 65 varnumber_T result;
65 66
66 if (n2 == 0) 67 if (n2 == 0)
67 { 68 {
68 if (in_vim9script()) 69 if (in_vim9script())
70 {
69 emsg(_(e_divide_by_zero)); 71 emsg(_(e_divide_by_zero));
72 if (failed != NULL)
73 *failed = TRUE;
74 }
70 if (n1 == 0) 75 if (n1 == 0)
71 result = VARNUM_MIN; // similar to NaN 76 result = VARNUM_MIN; // similar to NaN
72 else if (n1 < 0) 77 else if (n1 < 0)
73 result = -VARNUM_MAX; 78 result = -VARNUM_MAX;
74 else 79 else
80 return result; 85 return result;
81 } 86 }
82 87
83 /* 88 /*
84 * Return "n1" modulus "n2", taking care of dividing by zero. 89 * Return "n1" modulus "n2", taking care of dividing by zero.
90 * If "failed" is not NULL set it to TRUE when dividing by zero fails.
85 */ 91 */
86 varnumber_T 92 varnumber_T
87 num_modulus(varnumber_T n1, varnumber_T n2) 93 num_modulus(varnumber_T n1, varnumber_T n2, int *failed)
88 { 94 {
89 if (n2 == 0 && in_vim9script()) 95 if (n2 == 0 && in_vim9script())
96 {
90 emsg(_(e_divide_by_zero)); 97 emsg(_(e_divide_by_zero));
98 if (failed != NULL)
99 *failed = TRUE;
100 }
91 return (n2 == 0) ? 0 : (n1 % n2); 101 return (n2 == 0) ? 0 : (n1 % n2);
92 } 102 }
93 103
94 #if defined(EBCDIC) || defined(PROTO) 104 #if defined(EBCDIC) || defined(PROTO)
95 /* 105 /*
1514 tv_op(typval_T *tv1, typval_T *tv2, char_u *op) 1524 tv_op(typval_T *tv1, typval_T *tv2, char_u *op)
1515 { 1525 {
1516 varnumber_T n; 1526 varnumber_T n;
1517 char_u numbuf[NUMBUFLEN]; 1527 char_u numbuf[NUMBUFLEN];
1518 char_u *s; 1528 char_u *s;
1529 int failed = FALSE;
1519 1530
1520 // Can't do anything with a Funcref, Dict, v:true on the right. 1531 // Can't do anything with a Funcref, Dict, v:true on the right.
1521 if (tv2->v_type != VAR_FUNC && tv2->v_type != VAR_DICT 1532 if (tv2->v_type != VAR_FUNC && tv2->v_type != VAR_DICT
1522 && tv2->v_type != VAR_BOOL && tv2->v_type != VAR_SPECIAL) 1533 && tv2->v_type != VAR_BOOL && tv2->v_type != VAR_SPECIAL)
1523 { 1534 {
1597 switch (*op) 1608 switch (*op)
1598 { 1609 {
1599 case '+': n += tv_get_number(tv2); break; 1610 case '+': n += tv_get_number(tv2); break;
1600 case '-': n -= tv_get_number(tv2); break; 1611 case '-': n -= tv_get_number(tv2); break;
1601 case '*': n *= tv_get_number(tv2); break; 1612 case '*': n *= tv_get_number(tv2); break;
1602 case '/': n = num_divide(n, tv_get_number(tv2)); break; 1613 case '/': n = num_divide(n, tv_get_number(tv2),
1603 case '%': n = num_modulus(n, tv_get_number(tv2)); break; 1614 &failed); break;
1615 case '%': n = num_modulus(n, tv_get_number(tv2),
1616 &failed); break;
1604 } 1617 }
1605 clear_tv(tv1); 1618 clear_tv(tv1);
1606 tv1->v_type = VAR_NUMBER; 1619 tv1->v_type = VAR_NUMBER;
1607 tv1->vval.v_number = n; 1620 tv1->vval.v_number = n;
1608 } 1621 }
1617 s = concat_str(s, tv_get_string_buf(tv2, numbuf)); 1630 s = concat_str(s, tv_get_string_buf(tv2, numbuf));
1618 clear_tv(tv1); 1631 clear_tv(tv1);
1619 tv1->v_type = VAR_STRING; 1632 tv1->v_type = VAR_STRING;
1620 tv1->vval.v_string = s; 1633 tv1->vval.v_string = s;
1621 } 1634 }
1622 return OK; 1635 return failed ? FAIL : OK;
1623 1636
1624 case VAR_FLOAT: 1637 case VAR_FLOAT:
1625 #ifdef FEAT_FLOAT 1638 #ifdef FEAT_FLOAT
1626 { 1639 {
1627 float_T f; 1640 float_T f;
3194 rettv->vval.v_float = f1; 3207 rettv->vval.v_float = f1;
3195 } 3208 }
3196 else 3209 else
3197 #endif 3210 #endif
3198 { 3211 {
3212 int failed = FALSE;
3213
3199 if (op == '*') 3214 if (op == '*')
3200 n1 = n1 * n2; 3215 n1 = n1 * n2;
3201 else if (op == '/') 3216 else if (op == '/')
3202 n1 = num_divide(n1, n2); 3217 n1 = num_divide(n1, n2, &failed);
3203 else 3218 else
3204 n1 = num_modulus(n1, n2); 3219 n1 = num_modulus(n1, n2, &failed);
3220 if (failed)
3221 return FAIL;
3205 3222
3206 rettv->v_type = VAR_NUMBER; 3223 rettv->v_type = VAR_NUMBER;
3207 rettv->vval.v_number = n1; 3224 rettv->vval.v_number = n1;
3208 } 3225 }
3209 } 3226 }