summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2019-03-02 11:57:09 +0100
committerBram Moolenaar <Bram@vim.org>2019-03-02 11:57:09 +0100
commite21c1580b7acb598a6e3c38565434fe5d0e2ad7a (patch)
tree8c5cdc08fc2693ac8476825711cff24cb1b97aa5
parentbdace838c67c1bd94e55e34270a8325933891466 (diff)
downloadvim-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)
-rw-r--r--src/eval.c63
-rw-r--r--src/testdir/test_vimscript.vim39
-rw-r--r--src/version.c2
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,