]> granicus.if.org Git - vim/commitdiff
patch 8.2.4253: using freed memory when substitute with function call v8.2.4253
authorBram Moolenaar <Bram@vim.org>
Sat, 29 Jan 2022 14:21:51 +0000 (14:21 +0000)
committerBram Moolenaar <Bram@vim.org>
Sat, 29 Jan 2022 14:21:51 +0000 (14:21 +0000)
Problem:    Using freed memory when substitute uses a recursive function call.
Solution:   Make a copy of the substitute text.

src/ex_cmds.c
src/testdir/test_substitute.vim
src/version.c

index 099d9cfeedd78499193f0adebf81667cc06aa7c0..9d99571f72ab87819c81f9cfa461a4e0d891b4f0 100644 (file)
@@ -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;
index 0806fd2de6267e136f3cb217a5c1fc75eadad2b0..35b6b8a0245d39e3d1f38dda11ba067fd08e7409 100644 (file)
@@ -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
index e5499ade6628a22e25bcb0347705390a0c5ae1fc..25dcfe316bef2ce59587057e0feece3a13ea11f2 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4253,
 /**/
     4252,
 /**/