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:
@@ -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);
|
||||
|
@@ -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}()')
|
||||
|
@@ -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
|
||||
|
@@ -1833,6 +1833,22 @@ call_user_func(
|
||||
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.
|
||||
*/
|
||||
@@ -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
|
||||
{
|
||||
|
@@ -750,6 +750,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
2172,
|
||||
/**/
|
||||
2171,
|
||||
/**/
|
||||
|
@@ -606,6 +606,17 @@ call_ufunc(ufunc_T *ufunc, int argcount, ectx_T *ectx, isn_T *iptr)
|
||||
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)
|
||||
|
Reference in New Issue
Block a user