summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2024-04-22 21:04:29 +0200
committerChristian Brabandt <cb@256bit.org>2024-04-22 21:04:29 +0200
commit6b13e3d4e46393b3a35eed7c27ae020bcbd46a9b (patch)
treecdb2183a1eaed83c5a71dd1587eb1aec6ca11fe3
parent22697b6179e38f3d321b1495ef17f06031a9c8f1 (diff)
patch 9.1.0365: Crash when typing many keys with D- modifierv9.1.0365
Problem: Crash when typing many keys with D- modifier (after 9.1.0227). Solution: Don't treat a 0x80 byte inside a special sequence as the start of a special sequence (zeertzjq). closes: #14613 Signed-off-by: zeertzjq <zeertzjq@outlook.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
-rw-r--r--src/getchar.c51
-rw-r--r--src/testdir/test_mapping.vim24
-rw-r--r--src/testdir/test_registers.vim13
-rw-r--r--src/version.c2
4 files changed, 50 insertions, 40 deletions
diff --git a/src/getchar.c b/src/getchar.c
index 4e1c48c523..1c544da634 100644
--- a/src/getchar.c
+++ b/src/getchar.c
@@ -1286,12 +1286,11 @@ del_typebuf(int len, int offset)
*/
typedef struct
{
- int prev_c;
char_u buf[MB_MAXBYTES * 3 + 4];
+ int prev_c;
size_t buflen;
- unsigned pending;
- int in_special;
- int in_mbyte;
+ unsigned pending_special;
+ unsigned pending_mbyte;
} gotchars_state_T;
/*
@@ -1303,32 +1302,29 @@ gotchars_add_byte(gotchars_state_T *state, char_u byte)
{
int c = state->buf[state->buflen++] = byte;
int retval = FALSE;
+ int in_special = state->pending_special > 0;
+ int in_mbyte = state->pending_mbyte > 0;
- if (state->pending > 0)
- state->pending--;
-
- // When receiving a special key sequence, store it until we have all
- // the bytes and we can decide what to do with it.
- if ((state->pending == 0 || state->in_mbyte)
- && (c == K_SPECIAL
+ if (in_special)
+ state->pending_special--;
+ else if (c == K_SPECIAL
#ifdef FEAT_GUI
|| c == CSI
#endif
- ))
- {
- state->pending += 2;
- if (!state->in_mbyte)
- state->in_special = TRUE;
- }
+ )
+ // When receiving a special key sequence, store it until we have all
+ // the bytes and we can decide what to do with it.
+ state->pending_special = 2;
- if (state->pending > 0)
+ if (state->pending_special > 0)
goto ret_false;
- if (!state->in_mbyte)
+ if (in_mbyte)
+ state->pending_mbyte--;
+ else
{
- if (state->in_special)
+ if (in_special)
{
- state->in_special = FALSE;
if (state->prev_c == KS_MODIFIER)
// When receiving a modifier, wait for the modified key.
goto ret_false;
@@ -1341,16 +1337,11 @@ gotchars_add_byte(gotchars_state_T *state, char_u byte)
// When receiving a multibyte character, store it until we have all
// the bytes, so that it won't be split between two buffer blocks,
// and delete_buff_tail() will work properly.
- state->pending = MB_BYTE2LEN_CHECK(c) - 1;
- if (state->pending > 0)
- {
- state->in_mbyte = TRUE;
- goto ret_false;
- }
+ state->pending_mbyte = MB_BYTE2LEN_CHECK(c) - 1;
}
- else
- // Stored all bytes of a multibyte character.
- state->in_mbyte = FALSE;
+
+ if (state->pending_mbyte > 0)
+ goto ret_false;
retval = TRUE;
ret_false:
diff --git a/src/testdir/test_mapping.vim b/src/testdir/test_mapping.vim
index c98d5bf332..1175310465 100644
--- a/src/testdir/test_mapping.vim
+++ b/src/testdir/test_mapping.vim
@@ -248,21 +248,25 @@ func Test_map_meta_multibyte()
endfunc
func Test_map_super_quotes()
- if has('gui_gtk') || has('gui_gtk3') || has("macos")
- imap <D-"> foo
- call feedkeys("Go-\<*D-\">-\<Esc>", "xt")
- call assert_equal("-foo-", getline('$'))
- set nomodified
- iunmap <D-">
+ if "\<D-j>"[-1:] == '>'
+ throw 'Skipped: <D- modifier not supported'
endif
+
+ imap <D-"> foo
+ call feedkeys("Go-\<*D-\">-\<Esc>", "xt")
+ call assert_equal("-foo-", getline('$'))
+ set nomodified
+ iunmap <D-">
endfunc
func Test_map_super_multibyte()
- if has('gui_gtk') || has('gui_gtk3') || has("macos")
- imap <D-á> foo
- call assert_match('i <D-á>\s*foo', execute('imap'))
- iunmap <D-á>
+ if "\<D-j>"[-1:] == '>'
+ throw 'Skipped: <D- modifier not supported'
endif
+
+ imap <D-á> foo
+ call assert_match('i <D-á>\s*foo', execute('imap'))
+ iunmap <D-á>
endfunc
func Test_abbr_after_line_join()
diff --git a/src/testdir/test_registers.vim b/src/testdir/test_registers.vim
index 1d377bdd41..b2261d4d6c 100644
--- a/src/testdir/test_registers.vim
+++ b/src/testdir/test_registers.vim
@@ -261,6 +261,19 @@ func Test_zz_recording_with_select_mode_utf8_gui()
call Run_test_recording_with_select_mode_utf8()
endfunc
+func Test_recording_with_super_mod()
+ if "\<D-j>"[-1:] == '>'
+ throw 'Skipped: <D- modifier not supported'
+ endif
+
+ nnoremap <D-j> <Ignore>
+ let s = repeat("\<D-j>", 1000)
+ " This used to crash Vim
+ call feedkeys($'qr{s}q', 'tx')
+ call assert_equal(s, @r)
+ nunmap <D-j>
+endfunc
+
" Test for executing the last used register (@)
func Test_last_used_exec_reg()
" Test for the @: command
diff --git a/src/version.c b/src/version.c
index c67ee48b23..a863838dbd 100644
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 365,
+/**/
364,
/**/
363,