0
0
mirror of https://github.com/vim/vim.git synced 2025-09-23 03:43:49 -04:00

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.
This commit is contained in:
Bram Moolenaar
2020-12-20 21:10:17 +01:00
parent 61e07b2394
commit 5082471f91
6 changed files with 55 additions and 8 deletions

View File

@@ -18,6 +18,7 @@ int funcdepth_increment(void);
void funcdepth_decrement(void); void funcdepth_decrement(void);
int funcdepth_get(void); int funcdepth_get(void);
void funcdepth_restore(int depth); 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); 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 save_funccal(funccal_entry_T *entry);
void restore_funccal(void); void restore_funccal(void);

View File

@@ -470,6 +470,25 @@ def Test_call_wrong_args()
delete('Xscript') delete('Xscript')
enddef 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() def Test_call_lambda_args()
CheckDefFailure(['echo {i -> 0}()'], CheckDefFailure(['echo {i -> 0}()'],
'E119: Not enough arguments for function: {i -> 0}()') 'E119: Not enough arguments for function: {i -> 0}()')

View File

@@ -1312,12 +1312,12 @@ def Test_vim9script_reload_delfunc()
# FuncNo() is not redefined # FuncNo() is not redefined
writefile(first_lines + nono_lines, 'Xreloaded.vim') writefile(first_lines + nono_lines, 'Xreloaded.vim')
source Xreloaded.vim source Xreloaded.vim
g:DoCheck() g:DoCheck(false)
# FuncNo() is back # FuncNo() is back
writefile(first_lines + withno_lines, 'Xreloaded.vim') writefile(first_lines + withno_lines, 'Xreloaded.vim')
source Xreloaded.vim source Xreloaded.vim
g:DoCheck() g:DoCheck(false)
delete('Xreloaded.vim') delete('Xreloaded.vim')
enddef enddef

View File

@@ -1833,6 +1833,22 @@ call_user_func(
cleanup_function_call(fc); cleanup_function_call(fc);
} }
/*
* 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. * Call a user function after checking the arguments.
*/ */
@@ -1846,15 +1862,13 @@ call_user_func_check(
dict_T *selfdict) dict_T *selfdict)
{ {
int error; int error;
int regular_args = fp->uf_args.ga_len;
if (fp->uf_flags & FC_RANGE && funcexe->doesrange != NULL) if (fp->uf_flags & FC_RANGE && funcexe->doesrange != NULL)
*funcexe->doesrange = TRUE; *funcexe->doesrange = TRUE;
if (argcount < regular_args - fp->uf_def_args.ga_len) error = check_user_func_argcount(fp, argcount);
error = FCERR_TOOFEW; if (error != FCERR_UNKNOWN)
else if (!has_varargs(fp) && argcount > regular_args) return error;
error = FCERR_TOOMANY; if ((fp->uf_flags & FC_DICT) && selfdict == NULL)
else if ((fp->uf_flags & FC_DICT) && selfdict == NULL)
error = FCERR_DICT; error = FCERR_DICT;
else else
{ {

View File

@@ -750,6 +750,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
2172,
/**/ /**/
2171, 2171,
/**/ /**/

View File

@@ -606,6 +606,17 @@ call_ufunc(ufunc_T *ufunc, int argcount, ectx_T *ectx, isn_T *iptr)
return FAIL; return FAIL;
if (ufunc->uf_def_status == UF_COMPILED) 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 // The function has been compiled, can call it quickly. For a function
// that was defined later: we can call it directly next time. // that was defined later: we can call it directly next time.
if (iptr != NULL) if (iptr != NULL)