aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2022-04-04 13:02:32 +0800
committerGitHub <noreply@github.com>2022-04-04 13:02:32 +0800
commitdaa8ac051d9e641cb708af5ae2ffd571f5abbc44 (patch)
tree410fdd3af60b0ba3af8a67edde01818ba6a84a89
parentdb13f105d62e868997e61d8cef921fbebb312ddc (diff)
parentbbfc44e255ec6d1a6ced68dde64ff5d3c68b9ceb (diff)
downloadrneovim-daa8ac051d9e641cb708af5ae2ffd571f5abbc44.tar.gz
rneovim-daa8ac051d9e641cb708af5ae2ffd571f5abbc44.tar.bz2
rneovim-daa8ac051d9e641cb708af5ae2ffd571f5abbc44.zip
Merge pull request #17991 from zeertzjq/vim-8.2.4253
vim-patch:8.2.4253: using freed memory when substitute with function call
-rw-r--r--src/nvim/ex_cmds.c25
-rw-r--r--src/nvim/regexp.c4
-rw-r--r--src/nvim/shada.c2
-rw-r--r--src/nvim/testdir/test_substitute.vim18
4 files changed, 37 insertions, 12 deletions
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 71b3517adc..65cb544efd 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -3627,15 +3627,22 @@ 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);
+ sub = regtilde(sub, p_magic, preview);
// When previewing, the new pattern allocated by regtilde() needs to be freed
// in this function because it will not be used or freed by regtilde() later.
sub_needs_free = preview && sub != source;
@@ -4412,6 +4419,10 @@ skip:
}
vim_regfree(regmatch.regprog);
+ xfree(sub_copy);
+ if (sub_needs_free) {
+ xfree(sub);
+ }
// Restore the flag values, they can be used for ":&&".
subflags.do_all = save_do_all;
@@ -4444,10 +4455,6 @@ skip:
kv_destroy(preview_lines.subresults);
- if (sub_needs_free) {
- xfree(sub);
- }
-
return preview_buf;
#undef ADJUST_SUB_FIRSTLNUM
#undef PUSH_PREVIEW_LINES
diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c
index 53add57736..9a04cc428a 100644
--- a/src/nvim/regexp.c
+++ b/src/nvim/regexp.c
@@ -1531,7 +1531,7 @@ static fptr_T do_Lower(int *d, int c)
*
* The tildes are parsed once before the first call to vim_regsub().
*/
-char_u *regtilde(char_u *source, int magic)
+char_u *regtilde(char_u *source, int magic, bool preview)
{
char_u *newsub = source;
char_u *tmpsub;
@@ -1576,7 +1576,7 @@ char_u *regtilde(char_u *source, int magic)
}
// Only change reg_prev_sub when not previewing.
- if (!(State & CMDPREVIEW)) {
+ if (!preview) {
xfree(reg_prev_sub);
if (newsub != source) { // newsub was allocated, just keep it
reg_prev_sub = newsub;
diff --git a/src/nvim/shada.c b/src/nvim/shada.c
index b909888783..6c0add87d3 100644
--- a/src/nvim/shada.c
+++ b/src/nvim/shada.c
@@ -1238,7 +1238,7 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags)
// string is close to useless: you can only use it with :& or :~ and
// that’s all because s//~ is not available until the first call to
// regtilde. Vim was not calling this for some reason.
- (void)(char *)regtilde((char_u *)cur_entry.data.sub_string.sub, p_magic);
+ (void)(char *)regtilde((char_u *)cur_entry.data.sub_string.sub, p_magic, false);
// Do not free shada entry: its allocated memory was saved above.
break;
case kSDItemHistoryEntry:
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