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)