]> granicus.if.org Git - vim/commitdiff
patch 9.0.0873: using freed memory when executing mapclear at more prompt v9.0.0873
authorBram Moolenaar <Bram@vim.org>
Sun, 13 Nov 2022 20:43:19 +0000 (20:43 +0000)
committerBram Moolenaar <Bram@vim.org>
Sun, 13 Nov 2022 20:43:19 +0000 (20:43 +0000)
Problem:    Using freed memory when executing mapclear at the more prompt.
Solution:   Do not clear mappings while listing them. (closes #11438)

src/errors.h
src/map.c
src/testdir/test_mapping.vim
src/version.c

index ea33b04754afd64ce1ef2a52f4625285e7e6041b..88db28510ff8aafa59bb93997a4db58b0ffcc1f1 100644 (file)
@@ -3333,3 +3333,5 @@ EXTERN char e_argument_nr_trying_to_modify_const_str[]
 EXTERN char e_cannot_resize_window_in_another_tab_page[]
        INIT(= N_("E1308: Cannot resize a window in another tab page"));
 #endif
+EXTERN char e_cannot_change_mappings_while_listing[]
+       INIT(= N_("E1309: Cannot change mappings while listing"));
index fbbf9dcaf126f22fe15bfa255623aef593795bd3..4dec9e76ed88f6f0d0efb75bcb10eeb2b0cd8985 100644 (file)
--- a/src/map.c
+++ b/src/map.c
@@ -24,6 +24,10 @@ static mapblock_T    *first_abbr = NULL; // first entry in abbrlist
 static mapblock_T      *(maphash[256]);
 static int             maphash_valid = FALSE;
 
+// When non-zero then no mappings can be added or removed.  Prevents mappings
+// to change while listing them.
+static int             map_locked = 0;
+
 /*
  * Make a hash value for a mapping.
  * "mode" is the lower 4 bits of the State for the mapping.
@@ -150,11 +154,15 @@ showmap(
     if (message_filtered(mp->m_keys) && message_filtered(mp->m_str))
        return;
 
+    // Prevent mappings to be cleared while at the more prompt.
+    // Must jump to "theend" instead of returning.
+    ++map_locked;
+
     if (msg_didout || msg_silent != 0)
     {
        msg_putchar('\n');
        if (got_int)        // 'q' typed at MORE prompt
-           return;
+           goto theend;
     }
 
     mapchars = map_mode_to_chars(mp->m_mode);
@@ -200,6 +208,9 @@ showmap(
 #endif
     msg_clr_eos();
     out_flush();                       // show one line at a time
+
+theend:
+    --map_locked;
 }
 
     static int
@@ -298,6 +309,9 @@ list_mappings(
        int     mode,
        int     *did_local)
 {
+    // Prevent mappings to be cleared while at the more prompt.
+    ++map_locked;
+
     if (p_verbose > 0 && keyround == 1 && seenModifyOtherKeys)
        msg_puts(_("Seen modifyOtherKeys: true"));
 
@@ -337,6 +351,8 @@ list_mappings(
            }
        }
     }
+
+    --map_locked;
 }
 
 /*
@@ -954,6 +970,21 @@ map_clear(
     map_clear_mode(curbuf, mode, local, abbr);
 }
 
+/*
+ * If "map_locked" is set then give an error and return TRUE.
+ * Otherwise return FALSE.
+ */
+    static int
+is_map_locked(void)
+{
+    if (map_locked > 0)
+    {
+       emsg(_(e_cannot_change_mappings_while_listing));
+       return TRUE;
+    }
+    return FALSE;
+}
+
 /*
  * Clear all mappings in "mode".
  */
@@ -968,6 +999,9 @@ map_clear_mode(
     int                hash;
     int                new_hash;
 
+    if (is_map_locked())
+       return;
+
     validate_maphash();
 
     for (hash = 0; hash < 256; ++hash)
index f8e5a317f95f1fcc2327f55f046c0cb5269a57cf..4d5b202d40df1ade68e9522194247cca8e817967 100644 (file)
@@ -1774,5 +1774,29 @@ func Test_using_past_typeahead()
   nunmap :00
 endfunc
 
+func Test_mapclear_while_listing()
+  CheckRunVimInTerminal
+
+  let lines =<< trim END
+      set nocompatible
+      mapclear
+      for i in range(1, 999)
+        exe 'map ' .. 'foo' .. i .. ' bar'
+      endfor
+      au CmdlineLeave : call timer_start(0, {-> execute('mapclear')})
+  END
+  call writefile(lines, 'Xmapclear', 'D')
+  let buf = RunVimInTerminal('-S Xmapclear', {'rows': 10})
+
+  " this was using freed memory
+  call term_sendkeys(buf, ":map\<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 e8a1fa823a6cfe51c02ba92ea361ef8512eb4df3..5b4e34ee464e85a2c5f289ed84afcf8cf0755a43 100644 (file)
@@ -695,6 +695,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    873,
 /**/
     872,
 /**/