To: vim_dev@googlegroups.com Subject: Patch 8.1.0990 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.1.0990 Problem: Floating point exception with "%= 0" and "/= 0". Solution: Avoid dividing by zero. (Dominique Pelle, closes #4058) Files: src/eval.c, src/testdir/test_vimscript.vim *** ../vim-8.1.0989/src/eval.c 2019-02-20 22:04:28.823721308 +0100 --- src/eval.c 2019-03-02 11:55:06.947996350 +0100 *************** *** 253,258 **** --- 253,291 ---- /* 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,1765 **** 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; } } else if (opt_type == 0 && stringval != NULL) // string --- 1791,1798 ---- 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,2545 **** 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; } clear_tv(tv1); tv1->v_type = VAR_NUMBER; --- 2571,2578 ---- 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,4138 **** 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; ! } else ! { ! if (n2 == 0) /* give an error message? */ ! n1 = 0; ! else ! n1 = n1 % n2; ! } rettv->v_type = VAR_NUMBER; rettv->vval.v_number = n1; } --- 4146,4155 ---- if (op == '*') n1 = n1 * n2; else if (op == '/') ! n1 = num_divide(n1, n2); else ! n1 = num_modulus(n1, n2); ! rettv->v_type = VAR_NUMBER; rettv->vval.v_number = n1; } *** ../vim-8.1.0989/src/testdir/test_vimscript.vim 2019-02-12 22:28:27.845232664 +0100 --- src/testdir/test_vimscript.vim 2019-03-02 11:49:05.814627589 +0100 *************** *** 21,27 **** " " 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 " 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. --- 21,27 ---- " " 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 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,1462 **** --- 1457,1499 ---- 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' *** ../vim-8.1.0989/src/version.c 2019-03-02 10:13:36.800974804 +0100 --- src/version.c 2019-03-02 11:51:59.125366185 +0100 *************** *** 781,782 **** --- 781,784 ---- { /* Add new patch number below this line */ + /**/ + 990, /**/ -- Give a man a computer program and you give him a headache, but teach him to program computers and you give him the power to create headaches for others for the rest of his life... R. B. Forest /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///