summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2022-01-29 14:21:51 +0000
committerBram Moolenaar <Bram@vim.org>2022-01-29 14:21:51 +0000
commit37f47958b8a2a44abc60614271d9537e7f14e51a (patch)
tree93ecab84af2e5191851cef159b559f2267ef233e
parent4dc0dd869972ddafc7d9ee5ea765645b818a6dc9 (diff)
patch 8.2.4253: using freed memory when substitute with function callv8.2.4253
Problem: Using freed memory when substitute uses a recursive function call. Solution: Make a copy of the substitute text.
-rw-r--r--src/ex_cmds.c19
-rw-r--r--src/testdir/test_substitute.vim17
-rw-r--r--src/version.c2
3 files changed, 34 insertions, 4 deletions
diff --git a/src/ex_cmds.c b/src/ex_cmds.c
index 099d9cfeed..9d99571f72 100644
--- a/src/ex_cmds.c
+++ b/src/ex_cmds.c
@@ -3687,6 +3687,7 @@ ex_substitute(exarg_T *eap)
int save_do_all; // remember user specified 'g' flag
int save_do_ask; // remember user specified 'c' flag
char_u *pat = NULL, *sub = NULL; // init for GCC
+ char_u *sub_copy = NULL;
int delimiter;
int sublen;
int got_quit = FALSE;
@@ -3980,11 +3981,20 @@ ex_substitute(exarg_T *eap)
sub_firstline = NULL;
/*
- * ~ in the substitute pattern is replaced with the old pattern.
- * We do it here once to avoid it to be replaced over and over again.
- * But don't do it when it starts with "\=", then it's an expression.
+ * If the substitute pattern starts with "\=" then it's an expression.
+ * Make a copy, a recursive function may free it.
+ * Otherwise, '~' in the substitute pattern is replaced with the old
+ * pattern. We do it here once to avoid it to be replaced over and over
+ * again.
*/
- if (!(sub[0] == '\\' && sub[1] == '='))
+ if (sub[0] == '\\' && sub[1] == '=')
+ {
+ sub = vim_strsave(sub);
+ if (sub == NULL)
+ return;
+ sub_copy = sub;
+ }
+ else
sub = regtilde(sub, magic_isset());
/*
@@ -4790,6 +4800,7 @@ outofmem:
#endif
vim_regfree(regmatch.regprog);
+ vim_free(sub_copy);
// Restore the flag values, they can be used for ":&&".
subflags.do_all = save_do_all;
diff --git a/src/testdir/test_substitute.vim b/src/testdir/test_substitute.vim
index 0806fd2de6..35b6b8a024 100644
--- a/src/testdir/test_substitute.vim
+++ b/src/testdir/test_substitute.vim
@@ -980,4 +980,21 @@ func Test_substitute_gdefault()
bw!
endfunc
+" This was using "old_sub" after it was freed.
+func Test_using_old_sub()
+ set compatible maxfuncdepth=10
+ new
+ call setline(1, 'some text.')
+ func Repl()
+ ~
+ s/
+ endfunc
+ silent! s/\%')/\=Repl()
+
+ delfunc Repl
+ bwipe!
+ set nocompatible
+endfunc
+
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/version.c b/src/version.c
index e5499ade66..25dcfe316b 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 */
/**/
+ 4253,
+/**/
4252,
/**/
4251,