Fix an out of bounds memory access when drawing a multi line character with cursor below bottom margin

This commit is contained in:
Kovid Goyal 2026-09-24 18:49:35 +05:30
parent c9896e8c00
commit c02f932641
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
3 changed files with 34 additions and 5 deletions

View file

@ -199,6 +199,12 @@ you use a decent Wayland compositor.
Detailed list of changes
-------------------------------------
0.49.2 [future]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Fix an out-of-bounds memory access when drawing a multi-line text sized
character with the cursor below the bottom margin of the scroll region
0.49.1 [2026-09-24]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View file

@ -1568,11 +1568,19 @@ handle_fixed_width_multicell_command(Screen *self, CPUCell mcd, ListOfChars *lc)
cell_set_chars(&mcd, self->text_cache, lc);
move_cursor_past_multicell(self, width);
if (height > 1) {
index_type available_height = self->margin_bottom - self->cursor->y + 1;
if (height > available_height) {
index_type extra_lines = height - available_height;
screen_scroll(self, extra_lines);
self->cursor->y -= extra_lines;
if (self->cursor->y <= self->margin_bottom) {
index_type available_height = self->margin_bottom - self->cursor->y + 1;
if (height > available_height) {
index_type extra_lines = height - available_height;
screen_scroll(self, extra_lines);
self->cursor->y -= extra_lines;
}
} else {
// Cursor is below the scroll region, which cannot be scrolled, so
// move the cursor up until the cell fits on screen. height <=
// max_height <= lines so this cannot underflow.
index_type available_height = self->lines - self->cursor->y;
if (height > available_height) self->cursor->y -= height - available_height;
}
}
if (self->modes.mIRM) {

View file

@ -25,6 +25,21 @@ class TestMulticell(BaseTest):
s.draw('好好') # two 2-cell wide chars covering columns 0..3
s.test_draw_overlay_line('xy', xstart, 0) # would SIGSEGV without fix
def test_multicell_below_bottom_margin(self):
# Regression: with the cursor below the bottom margin, the available
# height computation underflowed and cells were written past the end
# of the line buffer.
s = self.create_screen(cols=10, lines=6)
s.set_margins(1, 3) # 1-based indexing
s.cursor.x, s.cursor.y = 0, s.lines - 1
multicell(s, 'A', scale=2)
self.ae((s.cursor.x, s.cursor.y), (2, s.lines - 2))
for y in (s.lines - 2, s.lines - 1):
for x in range(2):
c = s.cpu_cells(y, x)
self.assertIsNotNone(c['mcd'])
self.ae((c['x'], c['y'], c['mcd']['scale']), (x, y - s.lines + 2, 2))
def test_multicell(self: TestMulticell) -> None:
from kitty.tab_bar import as_rgb