Mercurial > vim
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 } |