Mercurial > vim
changeset 23252:35583da6397e v8.2.2172
patch 8.2.2172: Vim9: number of arguments is not always checked
Commit: https://github.com/vim/vim/commit/5082471f91dd42ed8c35e0f649d0a6572e6fe3fc
Author: Bram Moolenaar <Bram@vim.org>
Date: Sun Dec 20 21:10:17 2020 +0100
patch 8.2.2172: Vim9: number of arguments is not always checked
Problem: Vim9: number of arguments is not always checked. (Yegappan
Lakshmanan)
Solution: Check number of arguments when calling function by name.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sun, 20 Dec 2020 21:15:03 +0100 |
parents | 8caba5736a9a |
children | fe74b64d34e4 |
files | src/proto/userfunc.pro src/testdir/test_vim9_func.vim src/testdir/test_vim9_script.vim src/userfunc.c src/version.c src/vim9execute.c |
diffstat | 6 files changed, 55 insertions(+), 8 deletions(-) [+] |
line wrap: on
line diff
--- a/src/proto/userfunc.pro +++ b/src/proto/userfunc.pro @@ -18,6 +18,7 @@ int funcdepth_increment(void); 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);
--- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -470,6 +470,25 @@ def Test_call_wrong_args() delete('Xscript') enddef +def Test_call_funcref_wrong_args() + var head =<< trim END + vim9script + def Func3(a1: string, a2: number, a3: list<number>) + echo a1 .. a2 .. a3[0] + enddef + def Testme() + var funcMap: dict<func> = {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}()')
--- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -1312,12 +1312,12 @@ def Test_vim9script_reload_delfunc() # FuncNo() is not redefined writefile(first_lines + nono_lines, 'Xreloaded.vim') source Xreloaded.vim - g:DoCheck() + g:DoCheck(false) # FuncNo() is back writefile(first_lines + withno_lines, 'Xreloaded.vim') source Xreloaded.vim - g:DoCheck() + g:DoCheck(false) delete('Xreloaded.vim') enddef
--- a/src/userfunc.c +++ b/src/userfunc.c @@ -1834,6 +1834,22 @@ call_user_func( } /* + * 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,15 +1862,13 @@ call_user_func_check( 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 = check_user_func_argcount(fp, argcount); + if (error != FCERR_UNKNOWN) + return error; + if ((fp->uf_flags & FC_DICT) && selfdict == NULL) error = FCERR_DICT; else {
--- a/src/version.c +++ b/src/version.c @@ -751,6 +751,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 2172, +/**/ 2171, /**/ 2170,
--- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -606,6 +606,17 @@ call_ufunc(ufunc_T *ufunc, int argcount, 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)