From 9ab6c607ccc73f66ab90721f956c98bbca5cf267 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 17 Mar 2026 08:02:32 +0800 Subject: [PATCH] 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 https://github.com/vim/vim/commit/a5d9654620648ea6d3f2f8dc2a3e42de219cf860 Co-authored-by: Hirohito Higashi --- src/nvim/window.c | 2 +- test/old/testdir/test_window_cmd.vim | 64 ++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/src/nvim/window.c b/src/nvim/window.c index 2a68928a30..4df00525e1 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -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; } diff --git a/test/old/testdir/test_window_cmd.vim b/test/old/testdir/test_window_cmd.vim index 151f15fe02..496e5920fd 100644 --- a/test/old/testdir/test_window_cmd.vim +++ b/test/old/testdir/test_window_cmd.vim @@ -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\\", 'tx') + call feedkeys("ggMi" .. repeat("\", 99) .. "\", '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