To: vim_dev@googlegroups.com Subject: Patch 9.0.0877 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 9.0.0877 Problem: Using freed memory with :comclear while listing commands. Solution: Bail out when the command list has changed. (closes #11440) Files: src/usercmd.c, src/errors.h, src/testdir/test_usercommands.vim *** ../vim-9.0.0876/src/usercmd.c 2022-11-02 13:30:37.542314565 +0000 --- src/usercmd.c 2022-11-13 23:17:28.059292943 +0000 *************** *** 31,36 **** --- 31,39 ---- // List of all user commands. static garray_T ucmds = {0, 0, sizeof(ucmd_T), 4, NULL}; + // When non-zero it is not allowed to add or remove user commands + static int ucmd_locked = 0; + #define USER_CMD(i) (&((ucmd_T *)(ucmds.ga_data))[i]) #define USER_CMD_GA(gap, i) (&((ucmd_T *)((gap)->ga_data))[i]) *************** *** 499,504 **** --- 502,510 ---- long a; garray_T *gap; + // don't allow for adding or removing user commands here + ++ucmd_locked; + // In cmdwin, the alternative buffer should be used. gap = &prevwin_curwin()->w_buffer->b_ucmds; for (;;) *************** *** 656,661 **** --- 662,669 ---- if (!found) msg(_("No user-defined commands found")); + + --ucmd_locked; } char * *************** *** 1223,1228 **** --- 1231,1251 ---- } /* + * If ucmd_locked is set give an error and return TRUE. + * Otherwise return FALSE. + */ + static int + is_ucmd_locked(void) + { + if (ucmd_locked > 0) + { + emsg(_(e_cannot_change_user_commands_while_listing)); + return TRUE; + } + return FALSE; + } + + /* * Clear all user commands for "gap". */ void *************** *** 1231,1236 **** --- 1254,1262 ---- int i; ucmd_T *cmd; + if (is_ucmd_locked()) + return; + for (i = 0; i < gap->ga_len; ++i) { cmd = USER_CMD_GA(gap, i); *************** *** 1285,1290 **** --- 1311,1319 ---- return; } + if (is_ucmd_locked()) + return; + vim_free(cmd->uc_name); vim_free(cmd->uc_rep); # if defined(FEAT_EVAL) *** ../vim-9.0.0876/src/errors.h 2022-11-13 21:09:58.594211220 +0000 --- src/errors.h 2022-11-13 23:13:44.435120122 +0000 *************** *** 3339,3341 **** --- 3339,3343 ---- EXTERN char e_cannot_change_menus_while_listing[] INIT(= N_("E1310: Cannot change menus while listing")); #endif + EXTERN char e_cannot_change_user_commands_while_listing[] + INIT(= N_("E1311: Cannot change user commands while listing")); *** ../vim-9.0.0876/src/testdir/test_usercommands.vim 2022-10-18 13:11:18.466896436 +0100 --- src/testdir/test_usercommands.vim 2022-11-13 23:28:24.207745078 +0000 *************** *** 2,7 **** --- 2,10 ---- import './vim9.vim' as v9 + source check.vim + source screendump.vim + " Test for in user defined commands function Test_cmdmods() let g:mods = '' *************** *** 373,378 **** --- 376,389 ---- call feedkeys(":com MyCmd chist\\\"\", 'tx') call assert_equal("\"com MyCmd chistory", @:) + " delete the Check commands to avoid them showing up + call feedkeys(":com Check\\\"\", 'tx') + let cmds = substitute(@:, '"com ', '', '')->split() + for cmd in cmds + exe 'delcommand ' .. cmd + endfor + delcommand MissingFeature + command! DoCmd1 : command! DoCmd2 : call feedkeys(":com \\\"\", 'tx') *************** *** 716,721 **** --- 727,733 ---- echo 'hello' END call v9.CheckScriptFailure(lines, 'E1026:') + delcommand DoesNotEnd let lines =<< trim END command HelloThere { *************** *** 754,759 **** --- 766,772 ---- BadCommand END call v9.CheckScriptFailure(lines, 'E1128:') + delcommand BadCommand endfunc func Test_delcommand_buffer() *************** *** 817,823 **** call DefCmd('Command') let name = 'Command' ! while len(name) < 30 exe 'delcommand ' .. name let name ..= 'x' endwhile --- 830,836 ---- call DefCmd('Command') let name = 'Command' ! while len(name) <= 30 exe 'delcommand ' .. name let name ..= 'x' endwhile *************** *** 882,886 **** --- 895,924 ---- delcommand Rename endfunc + func Test_comclear_while_listing() + call CheckRunVimInTerminal() + + let lines =<< trim END + set nocompatible + comclear + for i in range(1, 999) + exe 'command ' .. 'Foo' .. i .. ' bar' + endfor + au CmdlineLeave : call timer_start(0, {-> execute('comclear')}) + END + call writefile(lines, 'Xcommandclear', 'D') + let buf = RunVimInTerminal('-S Xcommandclear', {'rows': 10}) + + " this was using freed memory + call term_sendkeys(buf, ":command\") + call TermWait(buf, 50) + call term_sendkeys(buf, "j") + call TermWait(buf, 50) + call term_sendkeys(buf, "G") + call term_sendkeys(buf, "\") + + call StopVimInTerminal(buf) + endfunc + " vim: shiftwidth=2 sts=2 expandtab *** ../vim-9.0.0876/src/version.c 2022-11-13 22:38:06.045883322 +0000 --- src/version.c 2022-11-13 22:56:32.170538849 +0000 *************** *** 697,698 **** --- 697,700 ---- { /* Add new patch number below this line */ + /**/ + 877, /**/ -- hundred-and-one symptoms of being an internet addict: 57. You begin to wonder how on earth your service provider is allowed to call 200 hours per month "unlimited." /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///