mirror of
https://github.com/neovim/neovim.git
synced 2026-04-20 14:25:32 +00:00
vim-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: vim/vim#19088#issuecomment-3710172769
closes: vim/vim#19186
fa64f92f6a
This commit is contained in:
@@ -718,13 +718,16 @@ bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last, bool i
|
|||||||
|
|
||||||
// Autocommands may have opened or closed windows for this buffer.
|
// Autocommands may have opened or closed windows for this buffer.
|
||||||
// Decrement the count for the close we do here.
|
// Decrement the count for the close we do here.
|
||||||
if (buf->b_nwindows > 0) {
|
// Don't decrement b_nwindows if the buffer wasn't displayed in any window
|
||||||
|
// before calling buf_freeall(),
|
||||||
|
if (nwindows > 0 && buf->b_nwindows > 0) {
|
||||||
buf->b_nwindows--;
|
buf->b_nwindows--;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the buffer from the list.
|
// Remove the buffer from the list.
|
||||||
// Do not wipe out the buffer if it is used in a window.
|
// Do not wipe out the buffer if it is used in a window, or if autocommands
|
||||||
if (wipe_buf && buf->b_nwindows <= 0) {
|
// wiped out all other buffers.
|
||||||
|
if (wipe_buf && buf->b_nwindows <= 0 && (buf->b_prev != NULL || buf->b_next != NULL)) {
|
||||||
if (clear_w_buf) {
|
if (clear_w_buf) {
|
||||||
win->w_buffer = NULL;
|
win->w_buffer = NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2765,6 +2765,9 @@ static void win_unclose_buffer(win_T *win, bufref_T *bufref, bool did_decrement)
|
|||||||
// If the buffer was removed from the window we have to give it any buffer.
|
// If the buffer was removed from the window we have to give it any buffer.
|
||||||
win->w_buffer = firstbuf;
|
win->w_buffer = firstbuf;
|
||||||
firstbuf->b_nwindows++;
|
firstbuf->b_nwindows++;
|
||||||
|
if (win == curwin) {
|
||||||
|
curbuf = curwin->w_buffer;
|
||||||
|
}
|
||||||
win_init_empty(win);
|
win_init_empty(win);
|
||||||
} else if (did_decrement && win->w_buffer == bufref->br_buf && bufref_valid(bufref)) {
|
} else if (did_decrement && win->w_buffer == bufref->br_buf && bufref_valid(bufref)) {
|
||||||
// close_buffer() decremented the window count, but we're keeping the window.
|
// close_buffer() decremented the window count, but we're keeping the window.
|
||||||
|
|||||||
@@ -862,6 +862,46 @@ func Test_BufUnload_close_other()
|
|||||||
call Run_test_BufUnload_close_other('setlocal bufhidden=wipe')
|
call Run_test_BufUnload_close_other('setlocal bufhidden=wipe')
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Run_test_BufUnload_tabonly(first_cmd)
|
||||||
|
exe a:first_cmd
|
||||||
|
tabnew Xa
|
||||||
|
setlocal bufhidden=wipe
|
||||||
|
tabprevious
|
||||||
|
autocmd BufWinLeave Xa ++once tabnext
|
||||||
|
autocmd BufUnload Xa ++once tabonly
|
||||||
|
tabonly
|
||||||
|
|
||||||
|
%bwipe!
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_BufUnload_tabonly()
|
||||||
|
" This used to dereference a NULL curbuf.
|
||||||
|
call Run_test_BufUnload_tabonly('setlocal bufhidden=hide')
|
||||||
|
" This used to dereference a NULL firstbuf.
|
||||||
|
call Run_test_BufUnload_tabonly('setlocal bufhidden=wipe')
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Run_test_BufUnload_tabonly_nested(second_autocmd)
|
||||||
|
file Xa
|
||||||
|
tabnew Xb
|
||||||
|
setlocal bufhidden=wipe
|
||||||
|
tabnew Xc
|
||||||
|
setlocal bufhidden=wipe
|
||||||
|
autocmd BufUnload Xb ++once ++nested bwipe! Xa
|
||||||
|
exe $'autocmd BufUnload Xa ++once ++nested {a:second_autocmd}'
|
||||||
|
autocmd BufWinLeave Xc ++once tabnext
|
||||||
|
tabfirst
|
||||||
|
2tabclose
|
||||||
|
|
||||||
|
%bwipe!
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_BufUnload_tabonly_nested()
|
||||||
|
" These used to cause heap-use-after-free.
|
||||||
|
call Run_test_BufUnload_tabonly_nested('tabonly')
|
||||||
|
call Run_test_BufUnload_tabonly_nested('tabonly | tabprevious')
|
||||||
|
endfunc
|
||||||
|
|
||||||
func s:AddAnAutocmd()
|
func s:AddAnAutocmd()
|
||||||
augroup vimBarTest
|
augroup vimBarTest
|
||||||
au BufReadCmd * echo 'hello'
|
au BufReadCmd * echo 'hello'
|
||||||
|
|||||||
Reference in New Issue
Block a user