diff options
| author | prwang <prwang@pku.edu.cn> | 2026-07-06 12:37:02 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-07-06 08:37:02 -0400 |
| commit | 732bf4db97d83d2874888cd6c1dacc7e9b422b81 (patch) | |
| tree | be57b531c2ecebd96305106591ac01c4aaa9cbdc /test/functional/vimscript/executable_spec.lua | |
| parent | a6827be98f4175c04bd10b5b7a53e883d2a4bf2a (diff) | |
| download | rneovim-732bf4db97d83d2874888cd6c1dacc7e9b422b81.tar.gz rneovim-732bf4db97d83d2874888cd6c1dacc7e9b422b81.tar.bz2 rneovim-732bf4db97d83d2874888cd6c1dacc7e9b422b81.zip | |
fix(input): stops accepting input after a large paste/input burst #40585
Problem:
Neovim can permanently stop accepting keyboard input after a large paste, or after
any sufficiently large input burst. The screen still redraws and honours window
resize, but typed keys have no effect and the session must be killed. A paste that
triggers the freeze is applied only partially.
Root cause:
`src/nvim/os/input.c` holds `input_buffer[INPUT_BUFFER_SIZE]` (16386 bytes),
compacted left rather than used as a ring:
- `input_get()` drains the buffer by advancing `input_read_pos`, but never rewinds
the cursors when it empties (`input_read_pos == input_write_pos`).
- The only rewind lives in `input_enqueue_raw()`, which `input_enqueue()` reaches
only inside `while (input_space() >= 19 && ptr < end)` (19 is the maximum
expansion of one `<x>` key form).
So once input fills the buffer to within 19 bytes of the top and is then fully
drained, the cursors are pinned near the top with `input_space() < 19`. The gate
never reopens, `input_enqueue()` never rewinds, and all further input is silently
dropped: `input_available()` stays 0 and the editor blocks forever in
`state_enter()` → `input_get()`. Redraw and resize run on independent paths, which
is why the UI looks alive while the keyboard is ignored.
Solution:
Rewind the read/write cursors when the buffer is empty, at the start of
`input_enqueue()`. The reset moves no data in the empty case and guarantees the
space gate can reopen; the non-empty case self-heals as the editor drains.
Test case:
A reproducer (no terminal required; drives `nvim --embed` over msgpack-RPC via
`nvim_input`) floods the input buffer, lets the editor drain it, then probes with
`:qa!`. It shows a sharp threshold at `INPUT_BUFFER_SIZE − 18`:
| `--fill` | master | with this fix |
|----------|-----------|---------------|
| ≤ 16367 | quits | quits |
| ≥ 16368 | **hangs** | quits |
- On current `master`, the freeze reproduces at `fill=16368`; the patched build
quits for every fill up to 100000.
- Interactive: a ~40 kB bracketed paste into Insert mode or a `:terminal` no longer
freezes.
Diffstat (limited to 'test/functional/vimscript/executable_spec.lua')
0 files changed, 0 insertions, 0 deletions