Mercurial > vim
diff src/usercmd.c @ 31085:8c10a0b22015 v9.0.0877
patch 9.0.0877: using freed memory with :comclear while listing commands
Commit: https://github.com/vim/vim/commit/cf2594fbf34d9a6776bd9d33f845cb8ceb1e1cd0
Author: Bram Moolenaar <Bram@vim.org>
Date: Sun Nov 13 23:30:06 2022 +0000
patch 9.0.0877: using freed memory with :comclear while listing commands
Problem: Using freed memory with :comclear while listing commands.
Solution: Bail out when the command list has changed. (closes https://github.com/vim/vim/issues/11440)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Mon, 14 Nov 2022 00:45:03 +0100 |
parents | 360f286b5869 |
children | 6c32d1072f82 |
line wrap: on
line diff
--- a/src/usercmd.c +++ b/src/usercmd.c @@ -31,6 +31,9 @@ typedef struct ucmd // 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,6 +502,9 @@ uc_list(char_u *name, size_t name_len) 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,6 +662,8 @@ uc_list(char_u *name, size_t name_len) if (!found) msg(_("No user-defined commands found")); + + --ucmd_locked; } char * @@ -1223,6 +1231,21 @@ ex_comclear(exarg_T *eap UNUSED) } /* + * 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,6 +1254,9 @@ uc_clear(garray_T *gap) 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,6 +1311,9 @@ ex_delcommand(exarg_T *eap) return; } + if (is_ucmd_locked()) + return; + vim_free(cmd->uc_name); vim_free(cmd->uc_rep); # if defined(FEAT_EVAL)