# HG changeset patch # User Bram Moolenaar # Date 1551524406 -3600 # Node ID 9cc42db77a54897fcf9a8d98593f039c0e1aa2ce # Parent 867ac4696428d3a93bd4180493081fa0684b16f9 patch 8.1.0990: floating point exception with "%= 0" and "/= 0" commit https://github.com/vim/vim/commit/e21c1580b7acb598a6e3c38565434fe5d0e2ad7a Author: Bram Moolenaar Date: Sat Mar 2 11:57:09 2019 +0100 patch 8.1.0990: floating point exception with "%= 0" and "/= 0" Problem: Floating point exception with "%= 0" and "/= 0". Solution: Avoid dividing by zero. (Dominique Pelle, closes https://github.com/vim/vim/issues/4058) diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -253,6 +253,39 @@ static char_u *find_option_end(char_u ** /* for VIM_VERSION_ defines */ #include "version.h" +/* + * Return "n1" divided by "n2", taking care of dividing by zero. + */ + static varnumber_T +num_divide(varnumber_T n1, varnumber_T n2) +{ + varnumber_T result; + + if (n2 == 0) // give an error message? + { + if (n1 == 0) + result = VARNUM_MIN; // similar to NaN + else if (n1 < 0) + result = -VARNUM_MAX; + else + result = VARNUM_MAX; + } + else + result = n1 / n2; + + return result; +} + +/* + * Return "n1" modulus "n2", taking care of dividing by zero. + */ + static varnumber_T +num_modulus(varnumber_T n1, varnumber_T n2) +{ + // Give an error when n2 is 0? + return (n2 == 0) ? 0 : (n1 % n2); +} + #if defined(EBCDIC) || defined(PROTO) /* @@ -1758,8 +1791,8 @@ ex_let_one( case '+': n = numval + n; break; case '-': n = numval - n; break; case '*': n = numval * n; break; - case '/': n = numval / n; break; - case '%': n = numval % n; break; + case '/': n = (long)num_divide(numval, n); break; + case '%': n = (long)num_modulus(numval, n); break; } } else if (opt_type == 0 && stringval != NULL) // string @@ -2538,8 +2571,8 @@ tv_op(typval_T *tv1, typval_T *tv2, char case '+': n += tv_get_number(tv2); break; case '-': n -= tv_get_number(tv2); break; case '*': n *= tv_get_number(tv2); break; - case '/': n /= tv_get_number(tv2); break; - case '%': n %= tv_get_number(tv2); break; + case '/': n = num_divide(n, tv_get_number(tv2)); break; + case '%': n = num_modulus(n, tv_get_number(tv2)); break; } clear_tv(tv1); tv1->v_type = VAR_NUMBER; @@ -4113,26 +4146,10 @@ eval6( if (op == '*') n1 = n1 * n2; else if (op == '/') - { - if (n2 == 0) /* give an error message? */ - { - if (n1 == 0) - n1 = VARNUM_MIN; /* similar to NaN */ - else if (n1 < 0) - n1 = -VARNUM_MAX; - else - n1 = VARNUM_MAX; - } - else - n1 = n1 / n2; - } + n1 = num_divide(n1, n2); else - { - if (n2 == 0) /* give an error message? */ - n1 = 0; - else - n1 = n1 % n2; - } + n1 = num_modulus(n1, n2); + rettv->v_type = VAR_NUMBER; rettv->vval.v_number = n1; } diff --git a/src/testdir/test_vimscript.vim b/src/testdir/test_vimscript.vim --- a/src/testdir/test_vimscript.vim +++ b/src/testdir/test_vimscript.vim @@ -21,7 +21,7 @@ com! -nargs=1 Xout call Xout(