# HG changeset patch # User Bram Moolenaar # Date 1668374102 -3600 # Node ID 082f526cfb96616cfd8e5bbb2e418e358b90ca78 # Parent e8915196437c983f8d8c8d8804d6077cdd8e084d patch 9.0.0874: using freed memory when executing unmenu at more prompt Commit: https://github.com/vim/vim/commit/920d311480114274e4d73156edf4b49ba0b712dd Author: Bram Moolenaar Date: Sun Nov 13 21:10:02 2022 +0000 patch 9.0.0874: using freed memory when executing unmenu at more prompt Problem: Using freed memory when executing unmenu at the more prompt. Solution: Do not clear menus while listing them. (closes https://github.com/vim/vim/issues/11439) diff --git a/src/errors.h b/src/errors.h --- a/src/errors.h +++ b/src/errors.h @@ -3335,3 +3335,7 @@ EXTERN char e_cannot_resize_window_in_an #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 diff --git a/src/menu.c b/src/menu.c --- a/src/menu.c +++ b/src/menu.c @@ -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 @@ -99,6 +103,21 @@ get_root_menu(char_u *name) } /* + * 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. */ void @@ -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 + // 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); - show_menus_recursive(parent, modes, 0); + --menus_locked; return OK; } diff --git a/src/testdir/test_menu.vim b/src/testdir/test_menu.vim --- a/src/testdir/test_menu.vim +++ b/src/testdir/test_menu.vim @@ -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\") + call TermWait(buf, 50) + call term_sendkeys(buf, "G") + call TermWait(buf, 50) + call term_sendkeys(buf, "\") + + call StopVimInTerminal(buf) +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -696,6 +696,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 874, +/**/ 873, /**/ 872,