From e2bd8600b873d2cd1f9d667c28cba8b1dba18839 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 18 May 2022 13:11:57 +0100 Subject: [PATCH] patch 8.2.4977: memory access error when substitute expression changes window Problem: Memory access error when substitute expression changes window. Solution: Disallow changing window in substitute expression. --- src/ex_cmds.c | 11 +++++++++++ src/testdir/test_substitute.vim | 13 +++++++++++++ src/version.c | 2 ++ 3 files changed, 26 insertions(+) Backport: Use textlock instead of textwinlock. In this version, textwinlock wasn't yet split out from textlock and it'll get merged back later. diff --git a/src/ex_cmds.c b/src/ex_cmds.c index 7e730becb48f..210e21fe7a5b 100644 --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -5576,12 +5576,17 @@ ex_substitute(exarg_T *eap) /* Save flags for recursion. They can change for e.g. * :s/^/\=execute("s#^##gn") */ subflags_save = subflags; + + /* Disallow changing text or switching window in an expression. */ + ++textlock; #endif /* get length of substitution part */ sublen = vim_regsub_multi(®match, sub_firstlnum - regmatch.startpos[0].lnum, sub, sub_firstline, FALSE, p_magic, TRUE); #ifdef FEAT_EVAL + --textlock; + /* Don't keep flags set by a recursive call. */ subflags = subflags_save; if (subflags.do_count) @@ -5670,9 +5675,15 @@ ex_substitute(exarg_T *eap) mch_memmove(new_end, sub_firstline + copycol, (size_t)copy_len); new_end += copy_len; +#ifdef FEAT_EVAL + ++textlock; +#endif (void)vim_regsub_multi(®match, sub_firstlnum - regmatch.startpos[0].lnum, sub, new_end, TRUE, p_magic, TRUE); +#ifdef FEAT_EVAL + --textlock; +#endif sub_nsubs++; did_sub = TRUE; diff --git a/src/testdir/test_substitute.vim b/src/testdir/test_substitute.vim index f3fd7ab1ce77..a1c324ed8d20 100644 --- a/src/testdir/test_substitute.vim +++ b/src/testdir/test_substitute.vim @@ -517,3 +517,16 @@ func Test_using_old_sub() set nocompatible endfunc +" This was switching windows in between computing the length and using it. +func Test_sub_change_window() + silent! lfile + sil! norm o0000000000000000000000000000000000000000000000000000 + func Repl() + lopen + endfunc + silent! s/\%')/\=Repl() + bwipe! + bwipe! + delfunc Repl +endfunc + diff --git a/src/version.c b/src/version.c index 4c63ea0771ad..782642b5d5a1 100644 --- a/src/version.c +++ b/src/version.c @@ -795,6 +795,8 @@ static char *(features[]) = 805, /**/ 5024, +/**/ + 4977, /**/ 4921, /**/