To: vim_dev@googlegroups.com Subject: Patch 8.2.2381 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.2381 Problem: Vim9: divide by zero does not abort expression execution. Solution: Use a "failed" flag. (issue #7704) Files: src/eval.c, src/proto/eval.pro, src/evalvars.c, src/vim9compile.c, src/testdir/vim9.vim, src/testdir/test_vim9_assign.vim *** ../vim-8.2.2380/src/eval.c 2021-01-20 21:23:10.709286927 +0100 --- src/eval.c 2021-01-21 12:33:26.969554466 +0100 *************** *** 57,72 **** /* * Return "n1" divided by "n2", taking care of dividing by zero. */ varnumber_T ! num_divide(varnumber_T n1, varnumber_T n2) { varnumber_T result; if (n2 == 0) { if (in_vim9script()) emsg(_(e_divide_by_zero)); if (n1 == 0) result = VARNUM_MIN; // similar to NaN else if (n1 < 0) --- 57,77 ---- /* * Return "n1" divided by "n2", taking care of dividing by zero. + * If "failed" is not NULL set it to TRUE when dividing by zero fails. */ varnumber_T ! num_divide(varnumber_T n1, varnumber_T n2, int *failed) { varnumber_T result; if (n2 == 0) { if (in_vim9script()) + { emsg(_(e_divide_by_zero)); + if (failed != NULL) + *failed = TRUE; + } if (n1 == 0) result = VARNUM_MIN; // similar to NaN else if (n1 < 0) *************** *** 82,93 **** /* * Return "n1" modulus "n2", taking care of dividing by zero. */ varnumber_T ! num_modulus(varnumber_T n1, varnumber_T n2) { if (n2 == 0 && in_vim9script()) emsg(_(e_divide_by_zero)); return (n2 == 0) ? 0 : (n1 % n2); } --- 87,103 ---- /* * Return "n1" modulus "n2", taking care of dividing by zero. + * If "failed" is not NULL set it to TRUE when dividing by zero fails. */ varnumber_T ! num_modulus(varnumber_T n1, varnumber_T n2, int *failed) { if (n2 == 0 && in_vim9script()) + { emsg(_(e_divide_by_zero)); + if (failed != NULL) + *failed = TRUE; + } return (n2 == 0) ? 0 : (n1 % n2); } *************** *** 1516,1521 **** --- 1526,1532 ---- varnumber_T n; char_u numbuf[NUMBUFLEN]; char_u *s; + int failed = FALSE; // Can't do anything with a Funcref, Dict, v:true on the right. if (tv2->v_type != VAR_FUNC && tv2->v_type != VAR_DICT *************** *** 1599,1606 **** 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; --- 1610,1619 ---- 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), ! &failed); break; ! case '%': n = num_modulus(n, tv_get_number(tv2), ! &failed); break; } clear_tv(tv1); tv1->v_type = VAR_NUMBER; *************** *** 1619,1625 **** tv1->v_type = VAR_STRING; tv1->vval.v_string = s; } ! return OK; case VAR_FLOAT: #ifdef FEAT_FLOAT --- 1632,1638 ---- tv1->v_type = VAR_STRING; tv1->vval.v_string = s; } ! return failed ? FAIL : OK; case VAR_FLOAT: #ifdef FEAT_FLOAT *************** *** 3196,3207 **** else #endif { 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; --- 3209,3224 ---- else #endif { + int failed = FALSE; + if (op == '*') n1 = n1 * n2; else if (op == '/') ! n1 = num_divide(n1, n2, &failed); else ! n1 = num_modulus(n1, n2, &failed); ! if (failed) ! return FAIL; rettv->v_type = VAR_NUMBER; rettv->vval.v_number = n1; *** ../vim-8.2.2380/src/proto/eval.pro 2021-01-15 18:04:40.102419940 +0100 --- src/proto/eval.pro 2021-01-21 12:02:06.733591844 +0100 *************** *** 1,6 **** /* eval.c */ ! varnumber_T num_divide(varnumber_T n1, varnumber_T n2); ! varnumber_T num_modulus(varnumber_T n1, varnumber_T n2); void eval_init(void); void eval_clear(void); void fill_evalarg_from_eap(evalarg_T *evalarg, exarg_T *eap, int skip); --- 1,6 ---- /* eval.c */ ! varnumber_T num_divide(varnumber_T n1, varnumber_T n2, int *failed); ! varnumber_T num_modulus(varnumber_T n1, varnumber_T n2, int *failed); void eval_init(void); void eval_clear(void); void fill_evalarg_from_eap(evalarg_T *evalarg, exarg_T *eap, int skip); *** ../vim-8.2.2380/src/evalvars.c 2021-01-17 20:52:08.602807027 +0100 --- src/evalvars.c 2021-01-21 11:57:13.934264435 +0100 *************** *** 1410,1417 **** 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 == gov_string --- 1410,1419 ---- case '+': n = numval + n; break; case '-': n = numval - n; break; case '*': n = numval * n; break; ! case '/': n = (long)num_divide(numval, n, ! &failed); break; ! case '%': n = (long)num_modulus(numval, n, ! &failed); break; } } else if (opt_type == gov_string *** ../vim-8.2.2380/src/vim9compile.c 2021-01-19 22:16:37.676519797 +0100 --- src/vim9compile.c 2021-01-21 11:58:21.934114758 +0100 *************** *** 4291,4299 **** && ppconst->pp_tv[ppconst_used].v_type == VAR_NUMBER && ppconst->pp_tv[ppconst_used + 1].v_type == VAR_NUMBER) { ! typval_T *tv1 = &ppconst->pp_tv[ppconst_used]; ! typval_T *tv2 = &ppconst->pp_tv[ppconst_used + 1]; ! varnumber_T res = 0; // both are numbers: compute the result switch (*op) --- 4291,4300 ---- && ppconst->pp_tv[ppconst_used].v_type == VAR_NUMBER && ppconst->pp_tv[ppconst_used + 1].v_type == VAR_NUMBER) { ! typval_T *tv1 = &ppconst->pp_tv[ppconst_used]; ! typval_T *tv2 = &ppconst->pp_tv[ppconst_used + 1]; ! varnumber_T res = 0; ! int failed = FALSE; // both are numbers: compute the result switch (*op) *************** *** 4301,4312 **** case '*': res = tv1->vval.v_number * tv2->vval.v_number; break; case '/': res = num_divide(tv1->vval.v_number, ! tv2->vval.v_number); break; case '%': res = num_modulus(tv1->vval.v_number, ! tv2->vval.v_number); break; } tv1->vval.v_number = res; --ppconst->pp_used; } --- 4302,4315 ---- case '*': res = tv1->vval.v_number * tv2->vval.v_number; break; case '/': res = num_divide(tv1->vval.v_number, ! tv2->vval.v_number, &failed); break; case '%': res = num_modulus(tv1->vval.v_number, ! tv2->vval.v_number, &failed); break; } + if (failed) + return FAIL; tv1->vval.v_number = res; --ppconst->pp_used; } *** ../vim-8.2.2380/src/testdir/vim9.vim 2020-12-20 15:43:27.667305001 +0100 --- src/testdir/vim9.vim 2021-01-21 12:11:13.172213246 +0100 *************** *** 69,74 **** --- 69,87 ---- endtry enddef + def CheckScriptFailureList(lines: list, errors: list, lnum = -3) + var cwd = getcwd() + var fname = 'XScriptFailure' .. s:sequence + s:sequence += 1 + writefile(lines, fname) + try + assert_fails('so ' .. fname, errors, lines, lnum) + finally + chdir(cwd) + delete(fname) + endtry + enddef + def CheckScriptSuccess(lines: list) var cwd = getcwd() var fname = 'XScriptSuccess' .. s:sequence *** ../vim-8.2.2380/src/testdir/test_vim9_assign.vim 2021-01-17 21:51:18.947791147 +0100 --- src/testdir/test_vim9_assign.vim 2021-01-21 12:31:55.637633996 +0100 *************** *** 1489,1494 **** --- 1489,1518 ---- assert_equal('', $ENVVAR) enddef + def Test_expr_error_no_assign() + var lines =<< trim END + vim9script + var x = invalid + echo x + END + CheckScriptFailureList(lines, ['E121:', 'E121:']) + + lines =<< trim END + vim9script + var x = 1 / 0 + echo x + END + CheckScriptFailureList(lines, ['E1154:', 'E121:']) + + lines =<< trim END + vim9script + var x = 1 % 0 + echo x + END + CheckScriptFailureList(lines, ['E1154:', 'E121:']) + enddef + + def Test_assign_command_modifier() var lines =<< trim END var verbose = 0 *** ../vim-8.2.2380/src/version.c 2021-01-20 22:22:45.740246955 +0100 --- src/version.c 2021-01-21 12:11:36.700151850 +0100 *************** *** 752,753 **** --- 752,755 ---- { /* Add new patch number below this line */ + /**/ + 2381, /**/ -- hundred-and-one symptoms of being an internet addict: 195. Your cat has its own home page. /// 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 ///