vim-patch:9.2.0180: possible crash with winminheight=0 (#38335)

Problem:  possible crash with winminheight=0
          (Emilien Breton)
Solution: Use <= instead of < when checking reserved room in
          frame_setheight() to correctly handle the zero-height
          boundary case (Hirohito Higashi).

In frame_setheight(), when shrinking the current window and the only
other window has 'winfixheight' with 'winminheight'=0, room_reserved
was not cleared because the condition used '<' instead of '<='.
The freed rows were discarded, leaving fr_height sum less than
topframe fr_height.  Subsequent resize operations then computed a
wrong room_cmdline that expanded topframe beyond the screen, causing
a crash.

fixes:  vim/vim#19706
closes: vim/vim#19712

a5d9654620

Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
This commit is contained in:
zeertzjq
2026-03-17 08:02:32 +08:00
committed by GitHub
parent 6edae88052
commit 9ab6c607cc
2 changed files with 65 additions and 1 deletions

View File

@@ -6311,7 +6311,7 @@ static void frame_setheight(frame_T *curfrp, int height)
}
// If there is only a 'winfixheight' window and making the
// window smaller, need to make the other window taller.
if (take < 0 && room - curfrp->fr_height < room_reserved) {
if (take < 0 && room - curfrp->fr_height <= room_reserved) {
room_reserved = 0;
}

View File

@@ -2326,4 +2326,68 @@ func Test_resize_from_another_tabpage()
call StopVimInTerminal(buf)
endfunc
" When shrinking a window and the only other window has 'winfixheight'
" with 'winminheight'=0, freed rows must go to the wfh window.
func Test_winfixheight_resize_wmh_zero()
set winminheight=0 laststatus=0
let id1 = win_getid()
copen
let id2 = win_getid()
wincmd w
wincmd _
let wi1 = getwininfo(id1)[0]
let wi2 = getwininfo(id2)[0]
let exp = &lines - wi1.status_height - wi2.height - wi2.status_height - &ch
call assert_equal([exp, 1], [wi1.height, wi1.status_height])
call assert_equal([0, 0], [wi2.height, wi2.status_height])
wincmd w " enter qf (height 0 -> 1)
let wi1 = getwininfo(id1)[0]
let wi2 = getwininfo(id2)[0]
let exp = &lines - wi1.status_height - wi2.height - wi2.status_height - &ch
call assert_equal(exp, wi1.height)
call assert_equal(1, wi2.height)
wincmd w
" Freed rows must go to qf (wfh, only other window).
" Before the fix, the rows were lost (fr_height sum < topframe fr_height),
" resulting in wrong window heights in subsequent operations.
1wincmd _
let wi1 = getwininfo(id1)[0]
let wi2 = getwininfo(id2)[0]
call assert_equal(1, wi1.height)
let exp = &lines - wi1.height - wi1.status_height - &ch
call assert_equal(exp, wi2.height)
wincmd w
99wincmd +
let wi1 = getwininfo(id1)[0]
let wi2 = getwininfo(id2)[0]
call assert_equal(0, wi1.height)
let exp = &lines - wi1.height - wi1.status_height - &ch
call assert_equal(exp, wi2.height)
99wincmd -
let wi1 = getwininfo(id1)[0]
let wi2 = getwininfo(id2)[0]
let exp = &lines - wi1.status_height - wi2.height - &ch
call assert_equal(exp, wi1.height)
call assert_equal(1, wi2.height)
" The original bug caused a crash here, but could not be reproduced in the
" test. Kept as-is, though it has no particular significance.
wincmd w
call feedkeys("999i\<CR>\<Esc>", 'tx')
call feedkeys("ggMi" .. repeat("\<CR>", 99) .. "\<Esc>", 'tx')
let wi1 = getwininfo(id1)[0]
let wi2 = getwininfo(id2)[0]
let exp = &lines - wi1.status_height - wi2.height - &ch
call assert_equal(exp, wi1.height)
call assert_equal(1, wi2.height)
cclose
set winminheight& laststatus&
endfunc
" vim: shiftwidth=2 sts=2 expandtab