summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2019-11-10 00:13:50 +0100
committerBram Moolenaar <Bram@vim.org>2019-11-10 00:13:50 +0100
commit4c054e9fb23027b55a09ee647a3a2c91936aeb1b (patch)
treed82b63c1d746e94f9f6ae1a8083fbdbd60f79612
parentee85702c10495041791f728e977b86005c4496e8 (diff)
patch 8.1.2282: crash when passing many arguments through a partialv8.1.2282
Problem: Crash when passing many arguments through a partial. (Andy Massimino) Solution: Check the number of arguments. (closes #5186)
-rw-r--r--src/evalfunc.c6
-rw-r--r--src/proto/userfunc.pro1
-rw-r--r--src/regexp.c14
-rw-r--r--src/testdir/test_expr.vim2
-rw-r--r--src/testdir/test_substitute.vim11
-rw-r--r--src/userfunc.c10
-rw-r--r--src/version.c2
7 files changed, 41 insertions, 5 deletions
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 62a7f06070..e5be361406 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -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)
diff --git a/src/proto/userfunc.pro b/src/proto/userfunc.pro
index b97e5f69a1..06f41e41ac 100644
--- a/src/proto/userfunc.pro
+++ b/src/proto/userfunc.pro
@@ -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);
diff --git a/src/regexp.c b/src/regexp.c
index 42f34c2f99..7fe891d319 100644
--- a/src/regexp.c
+++ b/src/regexp.c
@@ -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
diff --git a/src/testdir/test_expr.vim b/src/testdir/test_expr.vim
index 253cd49bc9..eb51cd6c1b 100644
--- a/src/testdir/test_expr.vim
+++ b/src/testdir/test_expr.vim
@@ -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()
diff --git a/src/testdir/test_substitute.vim b/src/testdir/test_substitute.vim
index b30464ff1a..c7532fbb4b 100644
--- a/src/testdir/test_substitute.vim
+++ b/src/testdir/test_substitute.vim
@@ -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.
diff --git a/src/userfunc.c b/src/userfunc.c
index cfc52befe4..6fa5854579 100644
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -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.
diff --git a/src/version.c b/src/version.c
index 9e00ea9f58..9d2025f3a7 100644
--- a/src/version.c
+++ b/src/version.c
@@ -742,6 +742,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 2282,
+/**/
2281,
/**/
2280,