summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2022-11-13 20:43:19 +0000
committerBram Moolenaar <Bram@vim.org>2022-11-13 20:43:19 +0000
commitbf533e4e88ebac8b8fec6d3e12dadc476ce9a1df (patch)
tree03a121b3a961d2e80710606819a8c6ca7000d648
parent623e94e13810e109c6aa201bcf3a8278429502f3 (diff)
patch 9.0.0873: using freed memory when executing mapclear at more promptv9.0.0873
Problem: Using freed memory when executing mapclear at the more prompt. Solution: Do not clear mappings while listing them. (closes #11438)
-rw-r--r--src/errors.h2
-rw-r--r--src/map.c36
-rw-r--r--src/testdir/test_mapping.vim24
-rw-r--r--src/version.c2
4 files changed, 63 insertions, 1 deletions
diff --git a/src/errors.h b/src/errors.h
index ea33b04754..88db28510f 100644
--- a/src/errors.h
+++ b/src/errors.h
@@ -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"));
diff --git a/src/map.c b/src/map.c
index fbbf9dcaf1..4dec9e76ed 100644
--- 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;
}
/*
@@ -955,6 +971,21 @@ map_clear(
}
/*
+ * 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".
*/
void
@@ -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)
diff --git a/src/testdir/test_mapping.vim b/src/testdir/test_mapping.vim
index f8e5a317f9..4d5b202d40 100644
--- a/src/testdir/test_mapping.vim
+++ b/src/testdir/test_mapping.vim
@@ -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
diff --git a/src/version.c b/src/version.c
index e8a1fa823a..5b4e34ee46 100644
--- 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 */
/**/
+ 873,
+/**/
872,
/**/
871,