mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
vim-patch:8.0.0486
Problem: Crash and endless loop when closing windows in a SessionLoadPost
autocommand.
Solution: Check for valid tabpage. (partly neovim/neovim#6308)
8c752bd6c4
Closes #6308
This commit is contained in:
parent
06ed7a189b
commit
b9e1289819
@ -6464,6 +6464,12 @@ win_found:
|
||||
win_remove(curwin, NULL);
|
||||
aucmd_win_used = false;
|
||||
last_status(false); // may need to remove last status line
|
||||
|
||||
if (!valid_tabpage_win(curtab)) {
|
||||
// no valid window in current tabpage
|
||||
close_tabpage(curtab);
|
||||
}
|
||||
|
||||
restore_snapshot(SNAP_AUCMD_IDX, false);
|
||||
(void)win_comp_pos(); // recompute window positions
|
||||
unblock_autocmds();
|
||||
|
@ -196,3 +196,71 @@ func Test_augroup_deleted()
|
||||
au! VimEnter
|
||||
endfunc
|
||||
|
||||
" Closing a window might cause an endless loop
|
||||
" E814 for older Vims
|
||||
function Test_autocmd_bufwipe_in_SessLoadPost()
|
||||
if has('win32')
|
||||
throw 'Skipped: test hangs on MS-Windows'
|
||||
endif
|
||||
tabnew
|
||||
set noswapfile
|
||||
let g:bufnr=bufnr('%')
|
||||
mksession!
|
||||
|
||||
let content=['set nocp noswapfile',
|
||||
\ 'let v:swapchoice="e"',
|
||||
\ 'augroup test_autocmd_sessionload',
|
||||
\ 'autocmd!',
|
||||
\ 'autocmd SessionLoadPost * 4bw!',
|
||||
\ 'augroup END'
|
||||
\ ]
|
||||
call writefile(content, 'Xvimrc')
|
||||
let a=system(v:progpath. ' --headless -u Xvimrc --noplugins -S Session.vim')
|
||||
call assert_match('E814', a)
|
||||
|
||||
unlet! g:bufnr
|
||||
set swapfile
|
||||
for file in ['Session.vim', 'Xvimrc']
|
||||
call delete(file)
|
||||
endfor
|
||||
endfunc
|
||||
|
||||
" SEGV occurs in older versions.
|
||||
function Test_autocmd_bufwipe_in_SessLoadPost2()
|
||||
if has('win32')
|
||||
throw 'Skipped: test hangs on MS-Windows'
|
||||
endif
|
||||
tabnew
|
||||
set noswapfile
|
||||
let g:bufnr=bufnr('%')
|
||||
mksession!
|
||||
|
||||
let content = ['set nocp noswapfile',
|
||||
\ 'function! DeleteInactiveBufs()',
|
||||
\ ' tabfirst',
|
||||
\ ' let tabblist = []',
|
||||
\ ' for i in range(1, tabpagenr(''$''))',
|
||||
\ ' call extend(tabblist, tabpagebuflist(i))',
|
||||
\ ' endfor',
|
||||
\ ' for b in range(1, bufnr(''$''))',
|
||||
\ ' if bufexists(b) && buflisted(b) && (index(tabblist, b) == -1 || bufname(b) =~# ''^$'')',
|
||||
\ ' exec ''bwipeout '' . b',
|
||||
\ ' endif',
|
||||
\ ' endfor',
|
||||
\ 'call append("1", "SessionLoadPost DONE")',
|
||||
\ 'endfunction',
|
||||
\ 'au SessionLoadPost * call DeleteInactiveBufs()']
|
||||
call writefile(content, 'Xvimrc')
|
||||
let a=system(v:progpath. ' --headless -u Xvimrc --noplugins -S Session.vim')
|
||||
" this probably only matches on unix
|
||||
if has("unix")
|
||||
call assert_notmatch('Caught deadly signal SEGV', a)
|
||||
endif
|
||||
call assert_match('SessionLoadPost DONE', a)
|
||||
|
||||
unlet! g:bufnr
|
||||
set swapfile
|
||||
for file in ['Session.vim', 'Xvimrc']
|
||||
call delete(file)
|
||||
endfor
|
||||
endfunc
|
||||
|
@ -1714,14 +1714,10 @@ static void win_equal_rec(
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* close all windows for buffer 'buf'
|
||||
*/
|
||||
void
|
||||
close_windows (
|
||||
buf_T *buf,
|
||||
int keep_curwin /* don't close "curwin" */
|
||||
)
|
||||
/// Closes all windows for buffer `buf`.
|
||||
///
|
||||
/// @param keep_curwin don't close `curwin`
|
||||
void close_windows(buf_T *buf, int keep_curwin)
|
||||
{
|
||||
tabpage_T *tp, *nexttp;
|
||||
int h = tabline_height();
|
||||
@ -1731,9 +1727,11 @@ close_windows (
|
||||
|
||||
for (win_T *wp = firstwin; wp != NULL && lastwin != firstwin; ) {
|
||||
if (wp->w_buffer == buf && (!keep_curwin || wp != curwin)
|
||||
&& !(wp->w_closing || wp->w_buffer->b_closing)
|
||||
) {
|
||||
win_close(wp, FALSE);
|
||||
&& !(wp->w_closing || wp->w_buffer->b_closing)) {
|
||||
if (win_close(wp, false) == FAIL) {
|
||||
// If closing the window fails give up, to avoid looping forever.
|
||||
break;
|
||||
}
|
||||
|
||||
/* Start all over, autocommands may change the window layout. */
|
||||
wp = firstwin;
|
||||
@ -3134,6 +3132,44 @@ bool valid_tabpage(tabpage_T *tpc) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Returns true when `tpc` is valid and at least one window is valid.
|
||||
int valid_tabpage_win(tabpage_T *tpc)
|
||||
{
|
||||
FOR_ALL_TABS(tp) {
|
||||
if (tp == tpc) {
|
||||
FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
|
||||
if (win_valid_any_tab(wp)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// shouldn't happen
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Close tabpage `tab`, assuming it has no windows in it.
|
||||
/// There must be another tabpage or this will crash.
|
||||
void close_tabpage(tabpage_T *tab)
|
||||
{
|
||||
tabpage_T *ptp;
|
||||
|
||||
if (tab == first_tabpage) {
|
||||
first_tabpage = tab->tp_next;
|
||||
ptp = first_tabpage;
|
||||
} else {
|
||||
for (ptp = first_tabpage; ptp != NULL && ptp->tp_next != tab;
|
||||
ptp = ptp->tp_next) {
|
||||
// do nothing
|
||||
}
|
||||
ptp->tp_next = tab->tp_next;
|
||||
}
|
||||
|
||||
goto_tabpage_tp(ptp, false, false);
|
||||
free_tabpage(tab);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find tab page "n" (first one is 1). Returns NULL when not found.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user