summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-12-20 21:10:17 +0100
committerBram Moolenaar <Bram@vim.org>2020-12-20 21:10:17 +0100
commit5082471f91dd42ed8c35e0f649d0a6572e6fe3fc (patch)
treefd05e598235e59d9db8c9565ef2429fb181a2a38
parent61e07b2394e12f757160cac421ec5c45dc4c074d (diff)
downloadvim-git-5082471f91dd42ed8c35e0f649d0a6572e6fe3fc.tar.gz
patch 8.2.2172: Vim9: number of arguments is not always checkedv8.2.2172
Problem: Vim9: number of arguments is not always checked. (Yegappan Lakshmanan) Solution: Check number of arguments when calling function by name.
-rw-r--r--src/proto/userfunc.pro1
-rw-r--r--src/testdir/test_vim9_func.vim19
-rw-r--r--src/testdir/test_vim9_script.vim4
-rw-r--r--src/userfunc.c26
-rw-r--r--src/version.c2
-rw-r--r--src/vim9execute.c11
6 files changed, 55 insertions, 8 deletions
diff --git a/src/proto/userfunc.pro b/src/proto/userfunc.pro
index 787d01090..c79c101c6 100644
--- 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);
diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim
index 61e909bfc..4a0c7a90c 100644
--- 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}()')
diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim
index b0e7635b0..5406391a7 100644
--- 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
diff --git a/src/userfunc.c b/src/userfunc.c
index b9fb644f1..f7ad9f391 100644
--- 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
{
diff --git a/src/version.c b/src/version.c
index d149c9b3f..f374d43e6 100644
--- 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,
diff --git a/src/vim9execute.c b/src/vim9execute.c
index 6409d88f1..606ce0cd3 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -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)