]> granicus.if.org Git - vim/commitdiff
patch 8.1.2282: crash when passing many arguments through a partial v8.1.2282
authorBram Moolenaar <Bram@vim.org>
Sat, 9 Nov 2019 23:13:50 +0000 (00:13 +0100)
committerBram Moolenaar <Bram@vim.org>
Sat, 9 Nov 2019 23:13:50 +0000 (00:13 +0100)
Problem:    Crash when passing many arguments through a partial. (Andy
            Massimino)
Solution:   Check the number of arguments. (closes #5186)

src/evalfunc.c
src/proto/userfunc.pro
src/regexp.c
src/testdir/test_expr.vim
src/testdir/test_substitute.vim
src/userfunc.c
src/version.c

index 62a7f06070ebef264ac891868e360902df39e036..e5be361406c52d7df2f0a5221ab9e2e124e4466b 100644 (file)
@@ -2527,6 +2527,12 @@ common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
                list = argvars[arg_idx].vval.v_list;
                if (list == NULL || list->lv_len == 0)
                    arg_idx = 0;
+               else if (list->lv_len > MAX_FUNC_ARGS)
+               {
+                   emsg_funcname((char *)e_toomanyarg, name);
+                   vim_free(name);
+                   goto theend;
+               }
            }
        }
        if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
index b97e5f69a1e74a1ba68920fb922ccd5afdecce6b..06f41e41acf2158a1a9f4f0cba54db5c698af422 100644 (file)
@@ -3,6 +3,7 @@ void func_init(void);
 hashtab_T *func_tbl_get(void);
 int get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate);
 char_u *deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload);
+void emsg_funcname(char *ermsg, char_u *name);
 int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, funcexe_T *funcexe);
 ufunc_T *find_func(char_u *name);
 void save_funccal(funccal_entry_T *entry);
index 42f34c2f9957622856c7b6045c18bb8f1979ef9f..7fe891d3195a0acfe6d05373b0a3c58148761dd2 100644 (file)
@@ -2015,12 +2015,18 @@ vim_regsub_both(
                    call_func(s, -1, &rettv, 1, argv, &funcexe);
                }
                if (matchList.sl_list.lv_len > 0)
-                   /* fill_submatch_list() was called */
+                   // fill_submatch_list() was called
                    clear_submatch_list(&matchList);
 
-               eval_result = tv_get_string_buf_chk(&rettv, buf);
-               if (eval_result != NULL)
-                   eval_result = vim_strsave(eval_result);
+               if (rettv.v_type == VAR_UNKNOWN)
+                   // something failed, no need to report another error
+                   eval_result = NULL;
+               else
+               {
+                   eval_result = tv_get_string_buf_chk(&rettv, buf);
+                   if (eval_result != NULL)
+                       eval_result = vim_strsave(eval_result);
+               }
                clear_tv(&rettv);
            }
            else
index 253cd49bc9cd20044d4eaba7083ab774a8d67776..eb51cd6c1bbb251292273f912de19a4e2c9a541b 100644 (file)
@@ -496,6 +496,8 @@ func Test_funcref()
   let OneByRef = 'One'->funcref()
   call assert_equal(2, OneByRef())
   call assert_fails('echo funcref("{")', 'E475:')
+  let OneByRef = funcref("One", repeat(["foo"], 20))
+  call assert_fails('let OneByRef = funcref("One", repeat(["foo"], 21))', 'E118:')
 endfunc
 
 func Test_setmatches()
index b30464ff1ac9d8637e6db154713518fbe36d7be6..c7532fbb4bd7467a444a9f745f755c135d226091 100644 (file)
@@ -408,9 +408,20 @@ endfunc
 func SubReplacer(text, submatches)
   return a:text .. a:submatches[0] .. a:text
 endfunc
+func SubReplacer20(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19, submatches)
+  return a:t3 .. a:submatches[0] .. a:t11
+endfunc
 
 func Test_substitute_partial()
    call assert_equal('1foo2foo3', substitute('123', '2', function('SubReplacer', ['foo']), 'g'))
+
+   " 19 arguments plus one is just OK
+   let Replacer = function('SubReplacer20', repeat(['foo'], 19))
+   call assert_equal('1foo2foo3', substitute('123', '2', Replacer, 'g'))
+
+   " 20 arguments plus one is too many
+   let Replacer = function('SubReplacer20', repeat(['foo'], 20))
+   call assert_fails("call substitute('123', '2', Replacer, 'g')", 'E118')
 endfunc
 
 " Tests for *sub-replace-special* and *sub-replace-expression* on :substitute.
index cfc52befe4aacd4ae3b407ce7eda2203cf043871..6fa5854579f9ab71b395430849fa1157ad1a1963 100644 (file)
@@ -408,7 +408,7 @@ deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload)
  * Give an error message with a function name.  Handle <SNR> things.
  * "ermsg" is to be passed without translation, use N_() instead of _().
  */
-    static void
+    void
 emsg_funcname(char *ermsg, char_u *name)
 {
     char_u     *p;
@@ -1537,7 +1537,14 @@ call_func(
        if (error == ERROR_NONE && partial->pt_argc > 0)
        {
            for (argv_clear = 0; argv_clear < partial->pt_argc; ++argv_clear)
+           {
+               if (argv_clear + argcount_in >= MAX_FUNC_ARGS)
+               {
+                   error = ERROR_TOOMANY;
+                   goto theend;
+               }
                copy_tv(&partial->pt_argv[argv_clear], &argv[argv_clear]);
+           }
            for (i = 0; i < argcount_in; ++i)
                argv[i + argv_clear] = argvars_in[i];
            argvars = argv;
@@ -1672,6 +1679,7 @@ call_func(
     if (error == ERROR_NONE)
        ret = OK;
 
+theend:
     /*
      * Report an error unless the argument evaluation or function call has been
      * cancelled due to an aborting error, an interrupt, or an exception.
index 9e00ea9f584b46d0790706cecbf1b337767e4594..9d2025f3a78a0a09754601c815593ada3cce0afa 100644 (file)
@@ -741,6 +741,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2282,
 /**/
     2281,
 /**/