aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/tui/tui.c4
-rw-r--r--test/functional/terminal/tui_spec.lua26
2 files changed, 29 insertions, 1 deletions
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index 3205547324..066567a87f 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -1635,11 +1635,13 @@ static void unibi_goto(UI *ui, int row, int col)
} \
if (str) { \
unibi_var_t vars[26 + 26]; \
+ unibi_var_t params[9]; \
size_t orig_pos = data->bufpos; \
memset(&vars, 0, sizeof(vars)); \
data->cork = true; \
retry: \
- unibi_format(vars, vars + 26, str, data->params, out, ui, pad, ui); \
+ memcpy(params, data->params, sizeof(params)); \
+ unibi_format(vars, vars + 26, str, params, out, ui, pad, ui); \
if (data->overflow) { \
data->bufpos = orig_pos; \
flush_buf(ui); \
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index 7c2269e453..e31f76a444 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -13,6 +13,7 @@ local feed_command = helpers.feed_command
local feed_data = thelpers.feed_data
local clear = helpers.clear
local command = helpers.command
+local dedent = helpers.dedent
local exec = helpers.exec
local testprg = helpers.testprg
local retry = helpers.retry
@@ -1443,6 +1444,31 @@ describe('TUI', function()
child_session:request('nvim_call_function', 'setcellwidths', {{{0x2103, 0x2103, 1}}})
screen:expect(singlewidth_screen, attrs)
end)
+
+ it('draws correctly when cursor_address overflows #21643', function()
+ helpers.skip(helpers.is_ci('github'), 'FIXME: flaky on GitHub CI')
+ screen:try_resize(75, 60)
+ -- The composing character takes 3 bytes.
+ local composing = ('a︠'):sub(2)
+ -- The composed character takes 1 + 5 * 3 = 16 bytes.
+ local c = 'a' .. composing:rep(5)
+ -- Going to top-left corner needs 3 bytes.
+ -- With screen width 75, 4088 characters need 54 full screen lines.
+ -- Drawing each full screen line needs 75 * 16 + 2 = 1202 bytes (2 bytes for CR LF).
+ -- The incomplete screen line needs 38 * 16 + 8 + 3 = 619 bytes.
+ -- The whole line needs 3 + 54 * 1202 + 619 = 65530 bytes.
+ -- The cursor_address that comes after will overflow the 65535-byte buffer.
+ local line = c:rep(4088) .. ('b'):rep(8) .. '℃'
+ child_session:request('nvim_buf_set_lines', 0, 0, -1, true, {line, 'c'})
+ screen:expect(
+ '{1:' .. c .. '}' .. c:rep(74) .. '|\n' .. (c:rep(75) .. '|\n'):rep(53)
+ .. c:rep(38) .. ('b'):rep(8) .. '℃' .. (' '):rep(28) .. '|\n' .. dedent([[
+ c |
+ {4:~ }|
+ {5:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |]]))
+ end)
end)
describe('TUI', function()