]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 8.2.2172: Vim9: number of arguments is not always checked v8.2.2172
authorBram Moolenaar <Bram@vim.org>
Sun, 20 Dec 2020 20:10:17 +0000 (21:10 +0100)
committerBram Moolenaar <Bram@vim.org>
Sun, 20 Dec 2020 20:10:17 +0000 (21:10 +0100)
Problem:    Vim9: number of arguments is not always checked. (Yegappan
            Lakshmanan)
Solution:   Check number of arguments when calling function by name.

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

index 787d01090896148e4c8aac337e86cdc6b5accb8f..c79c101c639e6b506ff38d066137f7da89d4e0cc 100644 (file)
@@ -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);
index 61e909bfc40954386a85cec71433df6fd7d32e28..4a0c7a90c0c5ed81a50e80950f90b7d863c3f049 100644 (file)
@@ -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}()')
index b0e7635b06f4ba6e780d62a812ae519a1507f6f9..5406391a76916f3aeb83e99c584972d970aa0f29 100644 (file)
@@ -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
index b9fb644f1d3a5fad0931612af04709f19595c7e0..f7ad9f391e05b6be0c9e623e8f5b74896ab2add0 100644 (file)
@@ -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
     {
index d149c9b3f610334bea9a44cba2ed6eabc8026e46..f374d43e662bf28e16c68ea7da5b55bd783ea752 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2172,
 /**/
     2171,
 /**/
index 6409d88f1bc10cf2330e6a489d55cd33c89c21c9..606ce0cd3595a0f60d6d316e941b341345f99dc0 100644 (file)
@@ -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)