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)