aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2022-04-04 11:15:31 +0800
committerzeertzjq <zeertzjq@outlook.com>2022-04-04 12:11:04 +0800
commit64869831171ffa455f35d1a1ce3a3f9c7e7416a2 (patch)
treeded0a099c6e9ef45dd3c2ab422f6f575ef449c25
parentdb13f105d62e868997e61d8cef921fbebb312ddc (diff)
downloadrneovim-64869831171ffa455f35d1a1ce3a3f9c7e7416a2.tar.gz
rneovim-64869831171ffa455f35d1a1ce3a3f9c7e7416a2.tar.bz2
rneovim-64869831171ffa455f35d1a1ce3a3f9c7e7416a2.zip
vim-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. https://github.com/vim/vim/commit/37f47958b8a2a44abc60614271d9537e7f14e51a 'compatible' doesn't seem needed for the test.
-rw-r--r--src/nvim/ex_cmds.c16
-rw-r--r--src/nvim/testdir/test_substitute.vim18
2 files changed, 30 insertions, 4 deletions
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 71b3517adc..830e764104 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -3627,13 +3627,20 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout, bool do_buf_event, handle
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.
assert(sub != NULL);
bool sub_needs_free = false;
- if (!(sub[0] == '\\' && sub[1] == '=')) {
+ char_u *sub_copy = NULL;
+
+ // 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] == '=') {
+ sub = vim_strsave(sub);
+ sub_copy = sub;
+ } else {
char_u *source = sub;
sub = regtilde(sub, p_magic);
// When previewing, the new pattern allocated by regtilde() needs to be freed
@@ -4412,6 +4419,7 @@ skip:
}
vim_regfree(regmatch.regprog);
+ xfree(sub_copy);
// Restore the flag values, they can be used for ":&&".
subflags.do_all = save_do_all;
diff --git a/src/nvim/testdir/test_substitute.vim b/src/nvim/testdir/test_substitute.vim
index 9710a7ab84..86fd0147a5 100644
--- a/src/nvim/testdir/test_substitute.vim
+++ b/src/nvim/testdir/test_substitute.vim
@@ -819,4 +819,22 @@ func Test_substitute_skipped_range()
bwipe!
endfunc
+" This was using "old_sub" after it was freed.
+func Test_using_old_sub()
+ " set compatible maxfuncdepth=10
+ set 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