mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00: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:
		| @@ -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,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. | ||||
|   // 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) { | ||||
|     // Close the link to the buffer. | ||||
|   | ||||
| @@ -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' | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 zeertzjq
					zeertzjq