mirror of
https://github.com/neovim/neovim.git
synced 2025-09-24 12:08:33 +00:00
vim-patch:9.1.1773: Crash in BufLeave after BufUnload closes other windows (#35830)
Problem: Crash in BufLeave/WinLeave/TabLeave when closing window after BufUnload closes all other windows in the tab page. Solution: Avoid duplicate BufLeave/WinLeave events. Trigger TabLeave before removing the buffer (zeertzjq). related: vim/vim#14166 related: neovim/neovim#33603 closes: vim/vim#183300c70820015
(cherry picked from commitc9f6267402
)
This commit is contained in:

committed by
github-actions[bot]
![github-actions[bot]](/assets/img/avatar_default.png)
parent
556d8d0002
commit
77fe01f200
@@ -2610,9 +2610,11 @@ static bool close_last_window_tabpage(win_T *win, bool free_buf, tabpage_T *prev
|
||||
// page and then close the window and the tab page. This avoids that
|
||||
// curwin and curtab are invalid while we are freeing memory, they may
|
||||
// be used in GUI events.
|
||||
// Don't trigger autocommands yet, they may use wrong values, so do
|
||||
// Don't trigger *Enter autocommands yet, they may use wrong values, so do
|
||||
// that below.
|
||||
goto_tabpage_tp(alt_tabpage(), false, true);
|
||||
// Do trigger *Leave autocommands, unless win->w_buffer is NULL, in which
|
||||
// case they have already been triggered.
|
||||
goto_tabpage_tp(alt_tabpage(), false, win->w_buffer != NULL);
|
||||
|
||||
// Safety check: Autocommands may have closed the window when jumping
|
||||
// to the other tab page.
|
||||
@@ -2906,6 +2908,14 @@ int win_close(win_T *win, bool free_buf, bool force)
|
||||
}
|
||||
}
|
||||
|
||||
if (ONE_WINDOW && curwin->w_locked && curbuf->b_locked_split
|
||||
&& first_tabpage->tp_next != NULL) {
|
||||
// The new curwin is the last window in the current tab page, and it is
|
||||
// already being closed. Trigger TabLeave now, as after its buffer is
|
||||
// removed it's no longer safe to do that.
|
||||
apply_autocmds(EVENT_TABLEAVE, NULL, NULL, false, curbuf);
|
||||
}
|
||||
|
||||
split_disallowed--;
|
||||
|
||||
// After closing the help window, try restoring the window layout from
|
||||
|
@@ -746,27 +746,49 @@ func Test_WinClosed_switch_tab()
|
||||
%bwipe!
|
||||
endfunc
|
||||
|
||||
" This used to trigger WinClosed twice for the same window, and the window's
|
||||
" buffer was NULL in the second autocommand.
|
||||
func Test_WinClosed_BufUnload_close_other()
|
||||
tabnew
|
||||
" This used to trigger WinClosed/WinLeave/BufLeave twice for the same window,
|
||||
" and the window's buffer was NULL in the second autocommand.
|
||||
func Run_test_BufUnload_close_other(extra_cmd)
|
||||
let oldtab = tabpagenr()
|
||||
tabnew Xb1
|
||||
let g:tab = tabpagenr()
|
||||
let g:buf = bufnr()
|
||||
new
|
||||
setlocal bufhidden=wipe
|
||||
augroup test-WinClosed
|
||||
autocmd BufUnload * ++once exe g:buf .. 'bwipe!'
|
||||
autocmd WinClosed * call tabpagebuflist(g:tab)
|
||||
let g:w1 = win_getid()
|
||||
new Xb2
|
||||
let g:w2 = win_getid()
|
||||
let g:log = []
|
||||
exe a:extra_cmd
|
||||
|
||||
augroup test-BufUnload-close-other
|
||||
autocmd BufUnload * ++nested ++once bwipe! Xb1
|
||||
for event in ['WinClosed', 'BufLeave', 'WinLeave', 'TabLeave']
|
||||
exe $'autocmd {event} * call tabpagebuflist(g:tab)'
|
||||
exe $'autocmd {event} * let g:log += ["{event}:" .. expand("<afile>")]'
|
||||
endfor
|
||||
augroup END
|
||||
|
||||
close
|
||||
" WinClosed is triggered once for each of the 2 closed windows.
|
||||
" Others are only triggered once.
|
||||
call assert_equal(['BufLeave:Xb2', 'WinLeave:Xb2', $'WinClosed:{g:w2}',
|
||||
\ $'WinClosed:{g:w1}', 'TabLeave:Xb2'], g:log)
|
||||
call assert_equal(oldtab, tabpagenr())
|
||||
call assert_equal([0, 0], win_id2tabwin(g:w1))
|
||||
call assert_equal([0, 0], win_id2tabwin(g:w2))
|
||||
|
||||
unlet g:tab
|
||||
unlet g:buf
|
||||
autocmd! test-WinClosed
|
||||
augroup! test-WinClosed
|
||||
unlet g:w1
|
||||
unlet g:w2
|
||||
unlet g:log
|
||||
autocmd! test-BufUnload-close-other
|
||||
augroup! test-BufUnload-close-other
|
||||
%bwipe!
|
||||
endfunc
|
||||
|
||||
func Test_BufUnload_close_other()
|
||||
call Run_test_BufUnload_close_other('')
|
||||
call Run_test_BufUnload_close_other('setlocal bufhidden=wipe')
|
||||
endfunc
|
||||
|
||||
func s:AddAnAutocmd()
|
||||
augroup vimBarTest
|
||||
au BufReadCmd * echo 'hello'
|
||||
|
Reference in New Issue
Block a user