mirror of
https://github.com/vim/vim.git
synced 2025-09-24 03:44:06 -04:00
patch 8.0.0486: crash and endless loop when closing windows in autocmd
Problem: Crash and endless loop when closing windows in a SessionLoadPost autocommand. Solution: Check for valid tabpage. (partly neovim #6308)
This commit is contained in:
@@ -9033,6 +9033,11 @@ win_found:
|
|||||||
win_remove(curwin, NULL);
|
win_remove(curwin, NULL);
|
||||||
aucmd_win_used = FALSE;
|
aucmd_win_used = FALSE;
|
||||||
last_status(FALSE); /* may need to remove last status line */
|
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);
|
restore_snapshot(SNAP_AUCMD_IDX, FALSE);
|
||||||
(void)win_comp_pos(); /* recompute window positions */
|
(void)win_comp_pos(); /* recompute window positions */
|
||||||
unblock_autocmds();
|
unblock_autocmds();
|
||||||
|
@@ -26,6 +26,8 @@ int win_new_tabpage(int after);
|
|||||||
int may_open_tabpage(void);
|
int may_open_tabpage(void);
|
||||||
int make_tabpages(int maxcount);
|
int make_tabpages(int maxcount);
|
||||||
int valid_tabpage(tabpage_T *tpc);
|
int valid_tabpage(tabpage_T *tpc);
|
||||||
|
int valid_tabpage_win(tabpage_T *tpc);
|
||||||
|
void close_tabpage(tabpage_T *tpc);
|
||||||
tabpage_T *find_tabpage(int n);
|
tabpage_T *find_tabpage(int n);
|
||||||
int tabpage_index(tabpage_T *ftp);
|
int tabpage_index(tabpage_T *ftp);
|
||||||
void goto_tabpage(int n);
|
void goto_tabpage(int n);
|
||||||
|
@@ -345,3 +345,66 @@ func Test_BufEnter()
|
|||||||
call delete('Xdir', 'd')
|
call delete('Xdir', 'd')
|
||||||
au! BufEnter
|
au! BufEnter
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
" Closing a window might cause an endless loop
|
||||||
|
" E814 for older Vims
|
||||||
|
function Test_autocmd_bufwipe_in_SessLoadPost()
|
||||||
|
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. ' -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()
|
||||||
|
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. ' -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
|
||||||
|
@@ -764,6 +764,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
486,
|
||||||
/**/
|
/**/
|
||||||
485,
|
485,
|
||||||
/**/
|
/**/
|
||||||
|
59
src/window.c
59
src/window.c
@@ -2107,7 +2107,7 @@ win_equal_rec(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* close all windows for buffer 'buf'
|
* Close all windows for buffer "buf".
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
close_windows(
|
close_windows(
|
||||||
@@ -2131,7 +2131,10 @@ close_windows(
|
|||||||
#endif
|
#endif
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
win_close(wp, FALSE);
|
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. */
|
/* Start all over, autocommands may change the window layout. */
|
||||||
wp = firstwin;
|
wp = firstwin;
|
||||||
@@ -3758,6 +3761,58 @@ valid_tabpage(tabpage_T *tpc)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return TRUE when "tpc" points to a valid tab page and at least one window is
|
||||||
|
* valid.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
valid_tabpage_win(tabpage_T *tpc)
|
||||||
|
{
|
||||||
|
tabpage_T *tp;
|
||||||
|
win_T *wp;
|
||||||
|
|
||||||
|
FOR_ALL_TABPAGES(tp)
|
||||||
|
{
|
||||||
|
if (tp == tpc)
|
||||||
|
{
|
||||||
|
FOR_ALL_WINDOWS_IN_TAB(tp, wp)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
;
|
||||||
|
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.
|
* Find tab page "n" (first one is 1). Returns NULL when not found.
|
||||||
*/
|
*/
|
||||||
|
Reference in New Issue
Block a user