Commit: patch 9.2.0990: libvterm: crash when a scroll region outlives a resize
Christian Brabandt <[email protected]>
| Newsgroups | gmane.editors.vim.devel |
|---|---|
| Message-ID | <[email protected]> |
patch 9.2.0990: libvterm: crash when a scroll region outlives a resize Commit: https://github.com/vim/vim/commit/cb34d15aeae530d6803ef4aa0618ec5b430df911 Author: Christian Brabandt <[email protected]> Date: Thu Aug 20 21:02:38 2026 +0000 patch 9.2.0990: libvterm: crash when a scroll region outlives a resize Problem: libvterms on_resize() clamps only the bottom and right edges of the scroll regions. When the terminal is made smaller, the top row can stay past the new last row. Every scroll after that builds a rectangle whose end row is before its start row, which inverts the clamping in scroll() and passes a negative height to memmove() as a huge size_t, so Vim crashes (Vadím Sukhomlínov). Solution: Clamp the near edges of the scroll regions on a resize too and drop a region that no longer makes sense. closes: #21099 Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Signed-off-by: Christian Brabandt <[email protected]> diff --git a/src/libvterm/src/state.c b/src/libvterm/src/state.c index 7a9732b58..138e95d07 100644 --- a/src/libvterm/src/state.c +++ b/src/libvterm/src/state.c @@ -122,6 +122,13 @@ static void scroll(VTermState *state, VTermRect rect, int downward, int rightwar if(!downward && !rightward) return; + // A degenerate rectangle makes "rows" or "cols" below negative, which + // inverts the clamping of "downward" and "rightward" and results in a + // negative height being passed to memmove(). This happens when a scroll + // region survives a resize that made the terminal smaller. + if(rect.end_row <= rect.start_row || rect.end_col <= rect.start_col) + return; + rows = rect.end_row - rect.start_row; if(downward > rows) downward = rows; @@ -2171,6 +2178,21 @@ static int on_resize(int rows, int cols, void *user) if(state->scrollregion_right > -1) UBOUND(state->scrollregion_right, state->cols); + // The near edges need clamping as well, otherwise a scroll region that + // was set before the terminal was made smaller can start past the last + // row or column. Drop a region that no longer makes sense, just like + // DECSTBM and DECSLRM do when it is set. + UBOUND(state->scrollregion_top, state->rows); + UBOUND(state->scrollregion_left, state->cols); + if(SCROLLREGION_BOTTOM(state) <= state->scrollregion_top) { + state->scrollregion_top = 0; + state->scrollregion_bottom = -1; + } + if(SCROLLREGION_RIGHT(state) <= state->scrollregion_left) { + state->scrollregion_left = 0; + state->scrollregion_right = -1; + } + VTermStateFields fields; fields.pos = state->pos; fields.lineinfos[0] = state->lineinfos[0]; diff --git a/src/testdir/test_terminal3.vim b/src/testdir/test_terminal3.vim index 263e9ee34..353505c39 100644 --- a/src/testdir/test_terminal3.vim +++ b/src/testdir/test_terminal3.vim @@ -1419,4 +1419,31 @@ func Test_terminal_rep_no_preceding_char() exe 'bwipe! ' .. buf endfunc +" This caused a Crash +func Test_terminal_scrollregion_resize_oob() + CheckUnix + CheckExecutable printf + + " A scroll region set before the terminal was made smaller kept its old top + " row, since on_resize() only clamped the bottom row. Every scroll after + " that used a rectangle that ends before it starts, which made libvterm pass + " a negative size to memmove(). + + " Sequences: set the scroll region to rows 5-9, shrink the terminal to three + " rows with CSI 8 ; rows ; cols t, then + " 1 SU, 2 SD, 3 a line feed at the bottom of the stale region + let seqs = ["\<ESC>[5;9r\<ESC>[8;3;40t\<ESC>[5S", + \ "\<ESC>[5;9r\<ESC>[8;3;40t\<ESC>[5T", + \ "\<ESC>[5;9r\<ESC>[8;3;40t "] + + for seq in seqs + let buf = term_start([&shell, &shellcmdflag, 'printf "%s" ' .. shellescape(seq)], + \ #{term_rows: 10, term_cols: 40}) + call TermWait(buf) + " Getting here without a crash (and no ASAN report) is the test. + call assert_true(bufexists(buf)) + exe 'bwipe! ' .. buf + endfor +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index 840e5cf8b..a2040e4eb 100644 --- a/src/version.c +++ b/src/version.c @@ -763,6 +763,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 990, /**/ 989, /**/ -- -- You received this message from the "vim_dev" maillist. Do not top-post! Type your reply below the text you are replying to. For more information, visit http://www.vim.org/maillist.php --- You received this message because you are subscribed to the Google Groups "vim_dev" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion visit https://groups.google.com/d/msgid/vim_dev/E1wxAKt-00E7Pj-Le%40256bit.org.