Skip to content

Commit fa64f92

Browse files
zeertzjqchrisbra
authored andcommitted
patch 9.1.2087: Crash when using :tabonly in BufUnload
Problem: Crash when using :tabonly in BufUnload. Solution: Set curbuf when setting curwin->w_buffer. Don't wipe out a buffer if there are no other buffers. Don't decrement b_nwindows if it was 0 before buf_freeall() (zeertzjq). fixes: #19088#issuecomment-3710172769 closes: #19186 Signed-off-by: zeertzjq <zeertzjq@outlook.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
1 parent a1895b6 commit fa64f92

4 files changed

Lines changed: 51 additions & 3 deletions

File tree

src/buffer.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -776,14 +776,18 @@ close_buffer(
776776

777777
// Autocommands may have opened or closed windows for this buffer.
778778
// Decrement the count for the close we do here.
779-
if (buf->b_nwindows > 0)
779+
// Don't decrement b_nwindows if the buffer wasn't displayed in any window
780+
// before calling buf_freeall(),
781+
if (nwindows > 0 && buf->b_nwindows > 0)
780782
--buf->b_nwindows;
781783

782784
/*
783785
* Remove the buffer from the list.
784-
* Do not wipe out the buffer if it is used in a window.
786+
* Do not wipe out the buffer if it is used in a window, or if autocommands
787+
* wiped out all other buffers.
785788
*/
786-
if (wipe_buf && buf->b_nwindows <= 0)
789+
if (wipe_buf && buf->b_nwindows <= 0
790+
&& (buf->b_prev != NULL || buf->b_next != NULL))
787791
{
788792
tabpage_T *tp;
789793
win_T *wp;

src/testdir/test_autocmd.vim

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -861,6 +861,46 @@ func Test_BufUnload_close_other()
861861
call Run_test_BufUnload_close_other('setlocal bufhidden=wipe')
862862
endfunc
863863

864+
func Run_test_BufUnload_tabonly(first_cmd)
865+
exe a:first_cmd
866+
tabnew Xa
867+
setlocal bufhidden=wipe
868+
tabprevious
869+
autocmd BufWinLeave Xa ++once tabnext
870+
autocmd BufUnload Xa ++once tabonly
871+
tabonly
872+
873+
%bwipe!
874+
endfunc
875+
876+
func Test_BufUnload_tabonly()
877+
" This used to dereference a NULL curbuf.
878+
call Run_test_BufUnload_tabonly('setlocal bufhidden=hide')
879+
" This used to dereference a NULL firstbuf.
880+
call Run_test_BufUnload_tabonly('setlocal bufhidden=wipe')
881+
endfunc
882+
883+
func Run_test_BufUnload_tabonly_nested(second_autocmd)
884+
file Xa
885+
tabnew Xb
886+
setlocal bufhidden=wipe
887+
tabnew Xc
888+
setlocal bufhidden=wipe
889+
autocmd BufUnload Xb ++once ++nested bwipe! Xa
890+
exe $'autocmd BufUnload Xa ++once ++nested {a:second_autocmd}'
891+
autocmd BufWinLeave Xc ++once tabnext
892+
tabfirst
893+
2tabclose
894+
895+
%bwipe!
896+
endfunc
897+
898+
func Test_BufUnload_tabonly_nested()
899+
" These used to cause heap-use-after-free.
900+
call Run_test_BufUnload_tabonly_nested('tabonly')
901+
call Run_test_BufUnload_tabonly_nested('tabonly | tabprevious')
902+
endfunc
903+
864904
func s:AddAnAutocmd()
865905
augroup vimBarTest
866906
au BufReadCmd * echo 'hello'

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,8 @@ static char *(features[]) =
734734

735735
static int included_patches[] =
736736
{ /* Add new patch number below this line */
737+
/**/
738+
2087,
737739
/**/
738740
2086,
739741
/**/

src/window.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3462,6 +3462,8 @@ win_close_othertab(win_T *win, int free_buf, tabpage_T *tp)
34623462
{
34633463
win->w_buffer = firstbuf;
34643464
++firstbuf->b_nwindows;
3465+
if (win == curwin)
3466+
curbuf = curwin->w_buffer;
34653467
win_init_empty(win);
34663468
}
34673469
return;

0 commit comments

Comments
 (0)