diff options
author | zeertzjq <zeertzjq@outlook.com> | 2024-03-10 07:03:36 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-03-10 07:03:36 +0800 |
commit | 448cf10c47e0678cee080baaf75f395511e13269 (patch) | |
tree | aa95dbd765da98a32d9638404a40addfa7cf292f | |
parent | 241c16129919e169b71ef1e788420224b358fbb3 (diff) | |
download | rneovim-448cf10c47e0678cee080baaf75f395511e13269.tar.gz rneovim-448cf10c47e0678cee080baaf75f395511e13269.tar.bz2 rneovim-448cf10c47e0678cee080baaf75f395511e13269.zip |
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
https://github.com/vim/vim/commit/b2ec0da080fb24f12a8d6f54bd7318a078ca4e6c
-rw-r--r-- | src/nvim/window.c | 23 | ||||
-rw-r--r-- | test/old/testdir/test_autocmd.vim | 21 |
2 files changed, 32 insertions, 12 deletions
diff --git a/src/nvim/window.c b/src/nvim/window.c index ecd2e83500..6c7ca86636 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -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 /// 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) 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); - if (only_one_window() && win_valid(win) && win->w_buffer == NULL - && (last_window(win) || curtab != prev_curtab - || close_last_window_tabpage(win, free_buf, prev_curtab)) - && !win->w_floating) { + if (win_valid(win) && win->w_buffer == NULL + && !win->w_floating && last_window(win)) { // Autocommands have closed all windows, quit now. Restore // curwin->w_buffer, otherwise writing ShaDa file may fail. 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) && win->w_buffer == 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); - unblock_autocmds(); return FAIL; } @@ -2940,10 +2935,14 @@ void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp) } // Fire WinClosed just before starting to free window-related resources. - do_autocmd_winclosed(win); - // autocmd may have freed the window already. - if (!win_valid_any_tab(win)) { - return; + // 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); + // autocmd may have freed the window already. + if (!win_valid_any_tab(win)) { + return; + } } if (win->w_buffer != NULL) { diff --git a/test/old/testdir/test_autocmd.vim b/test/old/testdir/test_autocmd.vim index 4d88573a1f..2b37ccf4a6 100644 --- a/test/old/testdir/test_autocmd.vim +++ b/test/old/testdir/test_autocmd.vim @@ -740,6 +740,27 @@ 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 + 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() augroup vimBarTest au BufReadCmd * echo 'hello' |