]> granicus.if.org Git - mutt/commitdiff
Fix infinite loop when help is bound to a named key combination.
authorKevin McCarthy <kevin@8t8.us>
Tue, 24 May 2016 19:08:46 +0000 (12:08 -0700)
committerKevin McCarthy <kevin@8t8.us>
Tue, 24 May 2016 19:08:46 +0000 (12:08 -0700)
Commit a07e8215a0ef introduced a bug in km_error_key, which is called
when an unbound key is pressed.

If help is bound to a sequence containing named keys (e.g. <esc>), the
raw (untokenized) string would be pushed back into the unget buffer.
This could lead to an infinite loop of unbound key presses triggering
more unbound keys being put into the unget buffer.

Change km_error_key to tokenize the string before putting it in the unget buffer.

Much thanks to Jiri Bohac for his bug report, analysis, and initial patch!

keymap.c

index 43a905044bba90492d503f9bd092facd72ec1368..09bef6bce7adea66f9109c424c370eba369d2a94 100644 (file)
--- a/keymap.c
+++ b/keymap.c
@@ -326,11 +326,10 @@ static char *get_func (const struct binding_t *bindings, int op)
 }
 
 /* Parses s for <function> syntax and adds the whole sequence to
- * the macro buffer.
- *
- * This should be used for macros, push, and exec commands only.
+ * either the macro or unget buffer.  This function is invoked by the next
+ * two defines below.
  */
-static void tokenize_push_macro_string (char *s)
+static void generic_tokenize_push_string (char *s, void (*generic_push) (int, int))
 {
   char *pp, *p = s + mutt_strlen (s) - 1;
   size_t l;
@@ -348,7 +347,7 @@ static void tokenize_push_macro_string (char *s)
       {
        if ((i = parse_fkey (pp)) > 0)
        {
-         mutt_push_macro_event (KEY_F (i), 0);
+         generic_push (KEY_F (i), 0);
          p = pp - 1;
          continue;
        }
@@ -362,7 +361,7 @@ static void tokenize_push_macro_string (char *s)
        if (KeyNames[i].name)
        {
          /* found a match */
-         mutt_push_macro_event (KeyNames[i].value, 0);
+         generic_push (KeyNames[i].value, 0);
          p = pp - 1;
          continue;
        }
@@ -382,16 +381,21 @@ static void tokenize_push_macro_string (char *s)
 
        if (op != OP_NULL)
        {
-         mutt_push_macro_event (0, op);
+         generic_push (0, op);
          p = pp - 1;
          continue;
        }
       }
     }
-    mutt_push_macro_event ((unsigned char)*p--, 0);    /* independent 8 bits chars */
+    generic_push ((unsigned char)*p--, 0);     /* independent 8 bits chars */
   }
 }
 
+/* This should be used for macros, push, and exec commands only. */
+#define tokenize_push_macro_string(s) generic_tokenize_push_string (s, mutt_push_macro_event)
+/* This should be used for other unget operations. */
+#define tokenize_unget_string(s) generic_tokenize_push_string (s, mutt_unget_event)
+
 static int retry_generic (int menu, keycode_t *keys, int keyslen, int lastkey)
 {
   if (menu != MENU_EDITOR && menu != MENU_GENERIC && menu != MENU_PAGER)
@@ -844,7 +848,7 @@ void km_error_key (int menu)
   }
 
   /* make sure the key is really the help key in this menu */
-  mutt_unget_string (buf);
+  tokenize_unget_string (buf);
   if (km_dokey (menu) != OP_HELP)
   {
     mutt_error _("Key is not bound.");