1
0
forked from aniani/vim

patch 8.2.0371: crash with combination of terminal popup and autocmd

Problem:    Crash with combination of terminal popup and autocmd.
Solution:   Disallow closing a popup that is the current window.  Add a check
            that the current buffer is valid. (closes #5754)
This commit is contained in:
Bram Moolenaar 2020-03-11 14:19:58 +01:00
parent e49b4bb895
commit cee52204ca
6 changed files with 53 additions and 2 deletions

View File

@ -508,6 +508,7 @@ close_buffer(
int wipe_buf = (action == DOBUF_WIPE || action == DOBUF_WIPE_REUSE);
int del_buf = (action == DOBUF_DEL || wipe_buf);
CHECK_CURBUF;
/*
* Force unloading or deleting when 'bufhidden' says so.
* The caller must take care of NOT deleting/freeing when 'bufhidden' is
@ -530,6 +531,7 @@ close_buffer(
#ifdef FEAT_TERMINAL
if (bt_terminal(buf) && (buf->b_nwindows == 1 || del_buf))
{
CHECK_CURBUF;
if (term_job_running(buf->b_term))
{
if (wipe_buf || unload_buf)
@ -554,6 +556,7 @@ close_buffer(
unload_buf = TRUE;
wipe_buf = TRUE;
}
CHECK_CURBUF;
}
#endif
@ -743,6 +746,7 @@ aucmd_abort:
if (del_buf)
buf->b_p_bl = FALSE;
}
// NOTE: at this point "curbuf" may be invalid!
}
/*
@ -933,7 +937,11 @@ free_buffer(buf_T *buf)
au_pending_free_buf = buf;
}
else
{
vim_free(buf);
if (curbuf == buf)
curbuf = NULL; // make clear it's not to be used
}
}
/*

View File

@ -364,8 +364,11 @@
# define ESTACK_CHECK_SETUP estack_len_before = exestack.ga_len;
# define ESTACK_CHECK_NOW if (estack_len_before != exestack.ga_len) \
siemsg("Exestack length expected: %d, actual: %d", estack_len_before, exestack.ga_len);
# define CHECK_CURBUF if (curwin != NULL && curwin->w_buffer != curbuf) \
iemsg("curbuf != curwin->w_buffer")
#else
# define ESTACK_CHECK_DECLARATION
# define ESTACK_CHECK_SETUP
# define ESTACK_CHECK_NOW
# define CHECK_CURBUF
#endif

View File

@ -2135,7 +2135,7 @@ popup_close_and_callback(win_T *wp, typval_T *arg)
break;
if (owp != NULL)
win_enter(owp, FALSE);
else if (win_valid(prevwin))
else if (win_valid(prevwin) && wp != prevwin)
win_enter(prevwin, FALSE);
else
win_enter(firstwin, FALSE);
@ -2147,11 +2147,13 @@ popup_close_and_callback(win_T *wp, typval_T *arg)
if (wp == curwin && ERROR_IF_POPUP_WINDOW)
return;
CHECK_CURBUF;
if (wp->w_close_cb.cb_name != NULL)
// Careful: This may make "wp" invalid.
invoke_popup_callback(wp, arg);
popup_close(id);
CHECK_CURBUF;
}
void
@ -2505,6 +2507,11 @@ popup_close(int id)
for (wp = first_popupwin; wp != NULL; prev = wp, wp = wp->w_next)
if (wp->w_id == id)
{
if (wp == curwin)
{
ERROR_IF_ANY_POPUP_WINDOW;
return;
}
if (prev == NULL)
first_popupwin = wp->w_next;
else
@ -2531,6 +2538,11 @@ popup_close_tabpage(tabpage_T *tp, int id)
for (wp = *root; wp != NULL; prev = wp, wp = wp->w_next)
if (wp->w_id == id)
{
if (wp == curwin)
{
ERROR_IF_ANY_POPUP_WINDOW;
return;
}
if (prev == NULL)
*root = wp->w_next;
else
@ -2881,10 +2893,11 @@ error_if_popup_window(int also_with_term UNUSED)
{
// win_execute() may set "curwin" to a popup window temporarily, but many
// commands are disallowed then. When a terminal runs in the popup most
// things are allowed.
// things are allowed. When a terminal is finished it can be closed.
if (WIN_IS_POPUP(curwin)
# ifdef FEAT_TERMINAL
&& (also_with_term || curbuf->b_term == NULL)
&& !term_is_finished(curbuf)
# endif
)
{

View File

@ -382,6 +382,7 @@ term_close_buffer(buf_T *buf, buf_T *old_curbuf)
curwin->w_buffer = curbuf;
++curbuf->b_nwindows;
}
CHECK_CURBUF;
// Wiping out the buffer will also close the window and call
// free_terminal().

View File

@ -2430,3 +2430,27 @@ func Test_hidden_terminal()
call assert_equal('', bufname('^$'))
call StopShellInTerminal(buf)
endfunc
func Test_term_nasty_callback()
func OpenTerms()
set hidden
let g:buf0 = term_start('sh', #{hidden: 1})
call popup_create(g:buf0, {})
let g:buf1 = term_start('sh', #{hidden: 1, term_finish: 'close'})
call popup_create(g:buf1, {})
let g:buf2 = term_start(['sh', '-c'], #{curwin: 1, exit_cb: function('TermExit')})
sleep 100m
call popup_close(win_getid())
endfunc
func TermExit(...)
call term_sendkeys(bufnr('#'), "exit\<CR>")
call popup_close(win_getid())
endfu
call OpenTerms()
call term_sendkeys(g:buf0, "exit\<CR>")
sleep 50m
exe g:buf0 .. 'bwipe'
set hidden&
endfunc

View File

@ -738,6 +738,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
371,
/**/
370,
/**/