]> granicus.if.org Git - vim/commitdiff
patch 9.0.0874: using freed memory when executing unmenu at more prompt v9.0.0874
authorBram Moolenaar <Bram@vim.org>
Sun, 13 Nov 2022 21:10:02 +0000 (21:10 +0000)
committerBram Moolenaar <Bram@vim.org>
Sun, 13 Nov 2022 21:10:02 +0000 (21:10 +0000)
Problem:    Using freed memory when executing unmenu at the more prompt.
Solution:   Do not clear menus while listing them. (closes #11439)

src/errors.h
src/menu.c
src/testdir/test_menu.vim
src/version.c

index 88db28510ff8aafa59bb93997a4db58b0ffcc1f1..99247b6d1914262730c0377b5f9bb0c9c4a674f0 100644 (file)
@@ -3335,3 +3335,7 @@ EXTERN char e_cannot_resize_window_in_another_tab_page[]
 #endif
 EXTERN char e_cannot_change_mappings_while_listing[]
        INIT(= N_("E1309: Cannot change mappings while listing"));
+#if defined(FEAT_MENU)
+EXTERN char e_cannot_change_menus_while_listing[]
+       INIT(= N_("E1310: Cannot change menus while listing"));
+#endif
index 432fbe972765a4cd05d4e26b8c31b5d629b6fa90..9209bf735cec9bb873a88e11ceb3fc493d7bcdd2 100644 (file)
@@ -46,6 +46,10 @@ static int s_tearoffs = FALSE;
 static int menu_is_hidden(char_u *name);
 static int menu_is_tearoff(char_u *name);
 
+// When non-zero no menu must be added or cleared.  Prevents the list of menus
+// changing while listing them.
+static int menus_locked = 0;
+
 #if defined(FEAT_MULTI_LANG) || defined(FEAT_TOOLBAR)
 static char_u *menu_skip_part(char_u *p);
 #endif
@@ -98,6 +102,21 @@ get_root_menu(char_u *name)
     return &root_menu;
 }
 
+/*
+ * If "menus_locked" is set then give an error and return TRUE.
+ * Otherwise return FALSE.
+ */
+    static int
+is_menus_locked(void)
+{
+    if (menus_locked > 0)
+    {
+       emsg(_(e_cannot_change_menus_while_listing));
+       return TRUE;
+    }
+    return FALSE;
+}
+
 /*
  * Do the :menu command and relatives.
  */
@@ -329,6 +348,9 @@ ex_menu(
     }
     else if (unmenu)
     {
+       if (is_menus_locked())
+           goto theend;
+
        /*
         * Delete menu(s).
         */
@@ -357,6 +379,9 @@ ex_menu(
     }
     else
     {
+       if (is_menus_locked())
+           goto theend;
+
        /*
         * Add menu(s).
         * Replace special key codes.
@@ -1147,11 +1172,14 @@ show_menus(char_u *path_name, int modes)
     }
     vim_free(path_name);
 
-    // Now we have found the matching menu, and we list the mappings
-                                                   // Highlight title
-    msg_puts_title(_("\n--- Menus ---"));
+    // make sure the list of menus doesn't change while listing them
+    ++menus_locked;
 
+    // list the matching menu mappings
+    msg_puts_title(_("\n--- Menus ---"));
     show_menus_recursive(parent, modes, 0);
+
+    --menus_locked;
     return OK;
 }
 
index 95d2b01a5c99abc55b0690eb6a5632d3feb17d97..65bdac23738d3d75bc25dddd2e25d7dc79804d0d 100644 (file)
@@ -3,6 +3,8 @@
 source check.vim
 CheckFeature menu
 
+source screendump.vim
+
 func Test_load_menu()
   try
     source $VIMRUNTIME/menu.vim
@@ -568,4 +570,28 @@ func Test_only_modifier()
   tunmenu a.b
 endfunc
 
+func Test_mapclear_while_listing()
+  CheckRunVimInTerminal
+
+  let lines =<< trim END
+      set nocompatible
+      unmenu *
+      for i in range(1, 999)
+        exe 'menu ' .. 'foo.' .. i .. ' bar'
+      endfor
+      au CmdlineLeave : call timer_start(0, {-> execute('unmenu *')})
+  END
+  call writefile(lines, 'Xmenuclear', 'D')
+  let buf = RunVimInTerminal('-S Xmenuclear', {'rows': 10})
+
+  " this was using freed memory
+  call term_sendkeys(buf, ":menu\<CR>")
+  call TermWait(buf, 50)
+  call term_sendkeys(buf, "G")
+  call TermWait(buf, 50)
+  call term_sendkeys(buf, "\<CR>")
+
+  call StopVimInTerminal(buf)
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
index 5b4e34ee464e85a2c5f289ed84afcf8cf0755a43..c6e074a63108e9b5f801522cd52a79c5de844cab 100644 (file)
@@ -695,6 +695,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    874,
 /**/
     873,
 /**/