]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.0.0875: using freed memory when executing delfunc at more prompt v9.0.0875
authorBram Moolenaar <Bram@vim.org>
Sun, 13 Nov 2022 22:13:33 +0000 (22:13 +0000)
committerBram Moolenaar <Bram@vim.org>
Sun, 13 Nov 2022 22:13:33 +0000 (22:13 +0000)
Problem:    Using freed memory when executing delfunc at the more prompt.
Solution:   Check function list not changed in another place. (closes #11437)

src/testdir/test_functions.vim
src/userfunc.c
src/version.c

index d0508ce7d1d048622bf1086e5858bfbf6ba433e9..cb072215d99562d147b15492f0d30346afc15074 100644 (file)
@@ -3026,4 +3026,31 @@ func Test_virtcol()
   bwipe!
 endfunc
 
+func Test_delfunc_while_listing()
+  CheckRunVimInTerminal
+
+  let lines =<< trim END
+      set nocompatible
+      for i in range(1, 999)
+        exe 'func ' .. 'MyFunc' .. i .. '()'
+        endfunc
+      endfor
+      au CmdlineLeave : call timer_start(0, {-> execute('delfunc MyFunc622')})
+  END
+  call writefile(lines, 'Xfunctionclear', 'D')
+  let buf = RunVimInTerminal('-S Xfunctionclear', {'rows': 12})
+
+  " This was using freed memory.  The height of the terminal must be so that
+  " the next function to be listed with "j" is the one that is deleted in the
+  " timer callback, tricky!
+  call term_sendkeys(buf, ":func /MyFunc\<CR>")
+  call TermWait(buf, 50)
+  call term_sendkeys(buf, "j")
+  call TermWait(buf, 50)
+  call term_sendkeys(buf, "\<CR>")
+
+  call StopVimInTerminal(buf)
+endfunc
+
+
 " vim: shiftwidth=2 sts=2 expandtab
index 64bc1f6fd0ba6b9df5a1e44f79b82474ca69f982..ff4cae7322fe1f14771eafaf395256001c2b6f78 100644 (file)
@@ -3792,15 +3792,36 @@ printable_func_name(ufunc_T *fp)
     return fp->uf_name_exp != NULL ? fp->uf_name_exp : fp->uf_name;
 }
 
+/*
+ * When "prev_ht_changed" does not equal "ht_changed" give an error and return
+ * TRUE.  Otherwise return FALSE.
+ */
+    static int
+function_list_modified(int prev_ht_changed)
+{
+    if (prev_ht_changed != func_hashtab.ht_changed)
+    {
+       emsg(_(e_function_list_was_modified));
+       return TRUE;
+    }
+    return FALSE;
+}
+
 /*
  * List the head of the function: "function name(arg1, arg2)".
  */
-    static void
+    static int
 list_func_head(ufunc_T *fp, int indent)
 {
+    int                prev_ht_changed = func_hashtab.ht_changed;
     int                j;
 
     msg_start();
+
+    // a timer at the more prompt may have deleted the function
+    if (function_list_modified(prev_ht_changed))
+       return FAIL;
+
     if (indent)
        msg_puts("   ");
     if (fp->uf_def_status != UF_NOT_COMPILED)
@@ -3877,6 +3898,8 @@ list_func_head(ufunc_T *fp, int indent)
     msg_clr_eos();
     if (p_verbose > 0)
        last_set_msg(fp->uf_script_ctx);
+
+    return OK;
 }
 
 /*
@@ -4315,7 +4338,7 @@ save_function_name(
     void
 list_functions(regmatch_T *regmatch)
 {
-    int                changed = func_hashtab.ht_changed;
+    int                prev_ht_changed = func_hashtab.ht_changed;
     long_u     todo = func_hashtab.ht_used;
     hashitem_T *hi;
 
@@ -4333,12 +4356,10 @@ list_functions(regmatch_T *regmatch)
                        : !isdigit(*fp->uf_name)
                            && vim_regexec(regmatch, fp->uf_name, 0)))
            {
-               list_func_head(fp, FALSE);
-               if (changed != func_hashtab.ht_changed)
-               {
-                   emsg(_(e_function_list_was_modified));
+               if (list_func_head(fp, FALSE) == FAIL)
+                   return;
+               if (function_list_modified(prev_ht_changed))
                    return;
-               }
            }
        }
     }
@@ -4542,28 +4563,39 @@ define_function(exarg_T *eap, char_u *name_arg, garray_T *lines_to_free)
 
            if (fp != NULL)
            {
-               list_func_head(fp, TRUE);
-               for (j = 0; j < fp->uf_lines.ga_len && !got_int; ++j)
-               {
-                   if (FUNCLINE(fp, j) == NULL)
-                       continue;
-                   msg_putchar('\n');
-                   msg_outnum((long)(j + 1));
-                   if (j < 9)
-                       msg_putchar(' ');
-                   if (j < 99)
-                       msg_putchar(' ');
-                   msg_prt_line(FUNCLINE(fp, j), FALSE);
-                   out_flush();        // show a line at a time
-                   ui_breakcheck();
-               }
-               if (!got_int)
+               // Check no function was added or removed from a timer, e.g. at
+               // the more prompt.  "fp" may then be invalid.
+               int prev_ht_changed = func_hashtab.ht_changed;
+
+               if (list_func_head(fp, TRUE) == OK)
                {
-                   msg_putchar('\n');
-                   if (fp->uf_def_status != UF_NOT_COMPILED)
-                       msg_puts("   enddef");
-                   else
-                       msg_puts("   endfunction");
+                   for (j = 0; j < fp->uf_lines.ga_len && !got_int; ++j)
+                   {
+                       if (FUNCLINE(fp, j) == NULL)
+                           continue;
+                       msg_putchar('\n');
+                       msg_outnum((long)(j + 1));
+                       if (j < 9)
+                           msg_putchar(' ');
+                       if (j < 99)
+                           msg_putchar(' ');
+                       if (function_list_modified(prev_ht_changed))
+                           break;
+                       msg_prt_line(FUNCLINE(fp, j), FALSE);
+                       out_flush();    // show a line at a time
+                       ui_breakcheck();
+                   }
+                   if (!got_int)
+                   {
+                       msg_putchar('\n');
+                       if (!function_list_modified(prev_ht_changed))
+                       {
+                           if (fp->uf_def_status != UF_NOT_COMPILED)
+                               msg_puts("   enddef");
+                           else
+                               msg_puts("   endfunction");
+                       }
+                   }
                }
            }
            else
index c6e074a63108e9b5f801522cd52a79c5de844cab..9a459eac465979dfe78bece7f1262a3808efde1f 100644 (file)
@@ -695,6 +695,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    875,
 /**/
     874,
 /**/