mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
vim-patch:9.1.0159: Crash in WinClosed after BufUnload closes other windows (#27792)
Problem: Crash in WinClosed after BufUnload closes other windows
Solution: Don't trigger WinClosed if the buffer is NULL (zeertzjq)
Now win_close_othertab() doesn't trigger any autocommands if the buffer
is NULL, so remove the autocmd blocking above (which was added not long
ago in patch v9.0.0550) for consistency.
Also remove an unreachable close_last_window_tabpage() above:
- It is only reached if only_one_window() returns TRUE and last_window()
returns FALSE.
- If only_one_window() returns TRUE, there is only one tabpage.
- If there is only one tabpage and last_window() returns FALSE, the
one_window() in last_window() must return FALSE, and the ONE_WINDOW
in close_last_window_tabpage() must also be FALSE.
- So close_last_window_tabpage() doesn't do anything and returns FALSE.
Then the curtab != prev_curtab check also doesn't make much sense, and
the only_one_window() can be replaced with a check for popup and a call
to last_window() since this is a stricter check than only_one_window().
closes: vim/vim#14166
b2ec0da080
This commit is contained in:
parent
241c161299
commit
448cf10c47
@ -2546,7 +2546,7 @@ bool can_close_in_cmdwin(win_T *win, Error *err)
|
|||||||
/// @param prev_curtab previous tabpage that will be closed if "win" is the
|
/// @param prev_curtab previous tabpage that will be closed if "win" is the
|
||||||
/// last window in the tabpage
|
/// last window in the tabpage
|
||||||
///
|
///
|
||||||
/// @return true when the window was closed already.
|
/// @return false if there are other windows and nothing is done, true otherwise.
|
||||||
static bool close_last_window_tabpage(win_T *win, bool free_buf, tabpage_T *prev_curtab)
|
static bool close_last_window_tabpage(win_T *win, bool free_buf, tabpage_T *prev_curtab)
|
||||||
FUNC_ATTR_NONNULL_ARG(1)
|
FUNC_ATTR_NONNULL_ARG(1)
|
||||||
{
|
{
|
||||||
@ -2751,10 +2751,8 @@ int win_close(win_T *win, bool free_buf, bool force)
|
|||||||
|
|
||||||
win_close_buffer(win, free_buf ? DOBUF_UNLOAD : 0, true);
|
win_close_buffer(win, free_buf ? DOBUF_UNLOAD : 0, true);
|
||||||
|
|
||||||
if (only_one_window() && win_valid(win) && win->w_buffer == NULL
|
if (win_valid(win) && win->w_buffer == NULL
|
||||||
&& (last_window(win) || curtab != prev_curtab
|
&& !win->w_floating && last_window(win)) {
|
||||||
|| close_last_window_tabpage(win, free_buf, prev_curtab))
|
|
||||||
&& !win->w_floating) {
|
|
||||||
// Autocommands have closed all windows, quit now. Restore
|
// Autocommands have closed all windows, quit now. Restore
|
||||||
// curwin->w_buffer, otherwise writing ShaDa file may fail.
|
// curwin->w_buffer, otherwise writing ShaDa file may fail.
|
||||||
if (curwin->w_buffer == NULL) {
|
if (curwin->w_buffer == NULL) {
|
||||||
@ -2766,10 +2764,7 @@ int win_close(win_T *win, bool free_buf, bool force)
|
|||||||
if (curtab != prev_curtab && win_valid_any_tab(win)
|
if (curtab != prev_curtab && win_valid_any_tab(win)
|
||||||
&& win->w_buffer == NULL) {
|
&& win->w_buffer == NULL) {
|
||||||
// Need to close the window anyway, since the buffer is NULL.
|
// Need to close the window anyway, since the buffer is NULL.
|
||||||
// Don't trigger autocmds with a NULL buffer.
|
|
||||||
block_autocmds();
|
|
||||||
win_close_othertab(win, false, prev_curtab);
|
win_close_othertab(win, false, prev_curtab);
|
||||||
unblock_autocmds();
|
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2940,11 +2935,15 @@ void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fire WinClosed just before starting to free window-related resources.
|
// Fire WinClosed just before starting to free window-related resources.
|
||||||
|
// If the buffer is NULL, it isn't safe to trigger autocommands,
|
||||||
|
// and win_close() should have already triggered WinClosed.
|
||||||
|
if (win->w_buffer != NULL) {
|
||||||
do_autocmd_winclosed(win);
|
do_autocmd_winclosed(win);
|
||||||
// autocmd may have freed the window already.
|
// autocmd may have freed the window already.
|
||||||
if (!win_valid_any_tab(win)) {
|
if (!win_valid_any_tab(win)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (win->w_buffer != NULL) {
|
if (win->w_buffer != NULL) {
|
||||||
// Close the link to the buffer.
|
// Close the link to the buffer.
|
||||||
|
@ -740,6 +740,27 @@ func Test_WinClosed_switch_tab()
|
|||||||
%bwipe!
|
%bwipe!
|
||||||
endfunc
|
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
|
||||||
|
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)
|
||||||
|
augroup END
|
||||||
|
close
|
||||||
|
|
||||||
|
unlet g:tab
|
||||||
|
unlet g:buf
|
||||||
|
autocmd! test-WinClosed
|
||||||
|
augroup! test-WinClosed
|
||||||
|
%bwipe!
|
||||||
|
endfunc
|
||||||
|
|
||||||
func s:AddAnAutocmd()
|
func s:AddAnAutocmd()
|
||||||
augroup vimBarTest
|
augroup vimBarTest
|
||||||
au BufReadCmd * echo 'hello'
|
au BufReadCmd * echo 'hello'
|
||||||
|
Loading…
Reference in New Issue
Block a user