To: vim_dev@googlegroups.com Subject: Patch 8.2.2172 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.2172 Problem: Vim9: number of arguments is not always checked. (Yegappan Lakshmanan) Solution: Check number of arguments when calling function by name. Files: src/userfunc.c, src/proto/userfunc.pro, src/vim9execute.c, src/testdir/test_vim9_func.vim, src/testdir/test_vim9_script.vim *** ../vim-8.2.2171/src/userfunc.c 2020-12-20 17:47:49.253182274 +0100 --- src/userfunc.c 2020-12-20 20:56:12.843590663 +0100 *************** *** 1834,1839 **** --- 1834,1855 ---- } /* + * Check the argument count for user function "fp". + * Return FCERR_UNKNOWN if OK, FCERR_TOOFEW or FCERR_TOOMANY otherwise. + */ + int + check_user_func_argcount(ufunc_T *fp, int argcount) + { + int regular_args = fp->uf_args.ga_len; + + if (argcount < regular_args - fp->uf_def_args.ga_len) + return FCERR_TOOFEW; + else if (!has_varargs(fp) && argcount > regular_args) + return FCERR_TOOMANY; + return FCERR_UNKNOWN; + } + + /* * Call a user function after checking the arguments. */ int *************** *** 1846,1860 **** dict_T *selfdict) { int error; - int regular_args = fp->uf_args.ga_len; if (fp->uf_flags & FC_RANGE && funcexe->doesrange != NULL) *funcexe->doesrange = TRUE; ! if (argcount < regular_args - fp->uf_def_args.ga_len) ! error = FCERR_TOOFEW; ! else if (!has_varargs(fp) && argcount > regular_args) ! error = FCERR_TOOMANY; ! else if ((fp->uf_flags & FC_DICT) && selfdict == NULL) error = FCERR_DICT; else { --- 1862,1874 ---- dict_T *selfdict) { int error; if (fp->uf_flags & FC_RANGE && funcexe->doesrange != NULL) *funcexe->doesrange = TRUE; ! error = check_user_func_argcount(fp, argcount); ! if (error != FCERR_UNKNOWN) ! return error; ! if ((fp->uf_flags & FC_DICT) && selfdict == NULL) error = FCERR_DICT; else { *** ../vim-8.2.2171/src/proto/userfunc.pro 2020-12-20 17:47:49.253182274 +0100 --- src/proto/userfunc.pro 2020-12-20 20:55:48.827682599 +0100 *************** *** 18,23 **** --- 18,24 ---- void funcdepth_decrement(void); int funcdepth_get(void); void funcdepth_restore(int depth); + int check_user_func_argcount(ufunc_T *fp, int argcount); int call_user_func_check(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rettv, funcexe_T *funcexe, dict_T *selfdict); void save_funccal(funccal_entry_T *entry); void restore_funccal(void); *** ../vim-8.2.2171/src/vim9execute.c 2020-12-20 17:47:49.253182274 +0100 --- src/vim9execute.c 2020-12-20 20:55:42.915705255 +0100 *************** *** 606,611 **** --- 606,622 ---- return FAIL; if (ufunc->uf_def_status == UF_COMPILED) { + int error = check_user_func_argcount(ufunc, argcount); + + if (error != FCERR_UNKNOWN) + { + if (error == FCERR_TOOMANY) + semsg(_(e_toomanyarg), ufunc->uf_name); + else + semsg(_(e_toofewarg), ufunc->uf_name); + return FAIL; + } + // The function has been compiled, can call it quickly. For a function // that was defined later: we can call it directly next time. if (iptr != NULL) *** ../vim-8.2.2171/src/testdir/test_vim9_func.vim 2020-12-20 17:47:49.257182258 +0100 --- src/testdir/test_vim9_func.vim 2020-12-20 21:04:35.512663131 +0100 *************** *** 470,475 **** --- 470,494 ---- delete('Xscript') enddef + def Test_call_funcref_wrong_args() + var head =<< trim END + vim9script + def Func3(a1: string, a2: number, a3: list) + echo a1 .. a2 .. a3[0] + enddef + def Testme() + var funcMap: dict = {func: Func3} + END + var tail =<< trim END + enddef + Testme() + END + CheckScriptSuccess(head + ["funcMap['func']('str', 123, [1, 2, 3])"] + tail) + + CheckScriptFailure(head + ["funcMap['func']('str', 123)"] + tail, 'E119:') + CheckScriptFailure(head + ["funcMap['func']('str', 123, [1], 4)"] + tail, 'E118:') + enddef + def Test_call_lambda_args() CheckDefFailure(['echo {i -> 0}()'], 'E119: Not enough arguments for function: {i -> 0}()') *** ../vim-8.2.2171/src/testdir/test_vim9_script.vim 2020-12-20 15:43:27.667305001 +0100 --- src/testdir/test_vim9_script.vim 2020-12-20 21:06:49.307724159 +0100 *************** *** 1312,1323 **** # FuncNo() is not redefined writefile(first_lines + nono_lines, 'Xreloaded.vim') source Xreloaded.vim ! g:DoCheck() # FuncNo() is back writefile(first_lines + withno_lines, 'Xreloaded.vim') source Xreloaded.vim ! g:DoCheck() delete('Xreloaded.vim') enddef --- 1312,1323 ---- # FuncNo() is not redefined writefile(first_lines + nono_lines, 'Xreloaded.vim') source Xreloaded.vim ! g:DoCheck(false) # FuncNo() is back writefile(first_lines + withno_lines, 'Xreloaded.vim') source Xreloaded.vim ! g:DoCheck(false) delete('Xreloaded.vim') enddef *** ../vim-8.2.2171/src/version.c 2020-12-20 17:59:49.314315870 +0100 --- src/version.c 2020-12-20 20:53:06.576304575 +0100 *************** *** 752,753 **** --- 752,755 ---- { /* Add new patch number below this line */ + /**/ + 2172, /**/ -- I recommend ordering large cargo containers of paper towels to make up whatever budget underruns you have. Paper products are always useful and they have the advantage of being completely flushable if you need to make room in the storage area later. (Scott Adams - The Dilbert principle) /// 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 ///