diff options
author | Bram Moolenaar <Bram@vim.org> | 2019-03-02 11:57:09 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2019-03-02 11:57:09 +0100 |
commit | e21c1580b7acb598a6e3c38565434fe5d0e2ad7a (patch) | |
tree | 8c5cdc08fc2693ac8476825711cff24cb1b97aa5 /src | |
parent | bdace838c67c1bd94e55e34270a8325933891466 (diff) | |
download | vim-git-e21c1580b7acb598a6e3c38565434fe5d0e2ad7a.tar.gz |
patch 8.1.0990: floating point exception with "%= 0" and "/= 0"v8.1.0990
Problem: Floating point exception with "%= 0" and "/= 0".
Solution: Avoid dividing by zero. (Dominique Pelle, closes #4058)
Diffstat (limited to 'src')
-rw-r--r-- | src/eval.c | 63 | ||||
-rw-r--r-- | src/testdir/test_vimscript.vim | 39 | ||||
-rw-r--r-- | src/version.c | 2 |
3 files changed, 80 insertions, 24 deletions
diff --git a/src/eval.c b/src/eval.c index 046688f0b..9e1ac6d99 100644 --- a/src/eval.c +++ b/src/eval.c @@ -253,6 +253,39 @@ static char_u *find_option_end(char_u **arg, int *opt_flags); /* 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_u *op) 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 index 41a1dda7d..57e673f3a 100644 --- a/src/testdir/test_vimscript.vim +++ b/src/testdir/test_vimscript.vim @@ -21,7 +21,7 @@ com! -nargs=1 Xout call Xout(<args>) " " Create a script that consists of the body of the function a:funcname. " Replace any ":return" by a ":finish", any argument variable by a global -" variable, and and every ":call" by a ":source" for the next following argument +" variable, and every ":call" by a ":source" for the next following argument " in the variable argument list. This function is useful if similar tests are " to be made for a ":return" from a function call or a ":finish" in a script " file. @@ -1457,6 +1457,43 @@ func Test_compound_assignment_operators() let x .= 'n' call assert_equal('2n', x) + " Test special cases: division or modulus with 0. + let x = 1 + let x /= 0 + if has('num64') + call assert_equal(0x7FFFFFFFFFFFFFFF, x) + else + call assert_equal(0x7fffffff, x) + endif + + let x = -1 + let x /= 0 + if has('num64') + call assert_equal(-0x7FFFFFFFFFFFFFFF, x) + else + call assert_equal(-0x7fffffff, x) + endif + + let x = 0 + let x /= 0 + if has('num64') + call assert_equal(-0x7FFFFFFFFFFFFFFF - 1, x) + else + call assert_equal(-0x7FFFFFFF - 1, x) + endif + + let x = 1 + let x %= 0 + call assert_equal(0, x) + + let x = -1 + let x %= 0 + call assert_equal(0, x) + + let x = 0 + let x %= 0 + call assert_equal(0, x) + " Test for string let x = 'str' let x .= 'ing' diff --git a/src/version.c b/src/version.c index 139657470..f9fea1c03 100644 --- a/src/version.c +++ b/src/version.c @@ -780,6 +780,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 990, +/**/ 989, /**/ 988, |