86 lines
2.5 KiB
Diff
86 lines
2.5 KiB
Diff
From 37f47958b8a2a44abc60614271d9537e7f14e51a Mon Sep 17 00:00:00 2001
|
|
From: Bram Moolenaar <Bram@vim.org>
|
|
Date: Sat, 29 Jan 2022 14:21:51 +0000
|
|
Subject: [PATCH] patch 8.2.4253: using freed memory when substitute with
|
|
function call
|
|
|
|
Problem: Using freed memory when substitute uses a recursive function call.
|
|
Solution: Make a copy of the substitute text.
|
|
---
|
|
src/ex_cmds.c | 19 +++++++++++++++----
|
|
src/testdir/test_substitute.vim | 16 ++++++++++++++++
|
|
2 files changed, 31 insertions(+), 4 deletions(-)
|
|
|
|
diff --git a/src/ex_cmds.c b/src/ex_cmds.c
|
|
index cccdf47..aa97b40 100644
|
|
--- a/src/ex_cmds.c
|
|
+++ b/src/ex_cmds.c
|
|
@@ -3577,6 +3577,7 @@ do_sub(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;
|
|
@@ -3866,11 +3867,20 @@ do_sub(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, p_magic);
|
|
|
|
/*
|
|
@@ -4670,6 +4680,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 c7532fb..3e6bc5c 100644
|
|
--- a/src/testdir/test_substitute.vim
|
|
+++ b/src/testdir/test_substitute.vim
|
|
@@ -745,3 +745,19 @@ func Test_sub_beyond_end()
|
|
call assert_equal('#', getline(1))
|
|
bwipe!
|
|
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
|
|
--
|
|
1.8.3.1
|
|
|