Patch 8.2.0371
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)
Files: src/macros.h, src/buffer.c, src/popupwin.c, src/terminal.c,
src/testdir/test_terminal.vim
*** ../vim-8.2.0370/src/macros.h 2020-02-28 22:19:38.310023356 +0100
--- src/macros.h 2020-03-11 12:23:55.990247931 +0100
***************
*** 364,371 ****
--- 364,374 ----
# 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
*** ../vim-8.2.0370/src/buffer.c 2020-02-08 18:35:12.528045466 +0100
--- src/buffer.c 2020-03-11 07:50:04.683125949 +0100
***************
*** 508,513 ****
--- 508,514 ----
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,535 ****
--- 531,537 ----
#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,559 ****
--- 556,562 ----
unload_buf = TRUE;
wipe_buf = TRUE;
}
+ CHECK_CURBUF;
}
#endif
***************
*** 743,748 ****
--- 746,752 ----
if (del_buf)
buf->b_p_bl = FALSE;
}
+ // NOTE: at this point "curbuf" may be invalid!
}
/*
***************
*** 933,939 ****
--- 937,947 ----
au_pending_free_buf = buf;
}
else
+ {
vim_free(buf);
+ if (curbuf == buf)
+ curbuf = NULL; // make clear it's not to be used
+ }
}
/*
*** ../vim-8.2.0370/src/popupwin.c 2020-03-06 21:43:14.414246402 +0100
--- src/popupwin.c 2020-03-11 14:03:58.633566371 +0100
***************
*** 2135,2141 ****
break;
if (owp != NULL)
win_enter(owp, FALSE);
! else if (win_valid(prevwin))
win_enter(prevwin, FALSE);
else
win_enter(firstwin, FALSE);
--- 2135,2141 ----
break;
if (owp != NULL)
win_enter(owp, FALSE);
! else if (win_valid(prevwin) && wp != prevwin)
win_enter(prevwin, FALSE);
else
win_enter(firstwin, FALSE);
***************
*** 2147,2157 ****
--- 2147,2159 ----
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,2510 ****
--- 2507,2517 ----
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,2536 ****
--- 2538,2548 ----
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,2890 ****
{
// 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.
if (WIN_IS_POPUP(curwin)
# ifdef FEAT_TERMINAL
&& (also_with_term || curbuf->b_term == NULL)
# endif
)
{
--- 2893,2903 ----
{
// 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. 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
)
{
*** ../vim-8.2.0370/src/terminal.c 2020-02-28 22:19:38.314023342 +0100
--- src/terminal.c 2020-03-10 19:53:06.484870815 +0100
***************
*** 382,387 ****
--- 382,388 ----
curwin->w_buffer = curbuf;
++curbuf->b_nwindows;
}
+ CHECK_CURBUF;
// Wiping out the buffer will also close the window and call
// free_terminal().
*** ../vim-8.2.0370/src/testdir/test_terminal.vim 2020-03-03 22:56:36.302382831 +0100
--- src/testdir/test_terminal.vim 2020-03-11 14:15:57.889585751 +0100
***************
*** 2430,2432 ****
--- 2430,2456 ----
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
+
*** ../vim-8.2.0370/src/version.c 2020-03-11 13:01:36.025436785 +0100
--- src/version.c 2020-03-11 14:16:19.989463949 +0100
***************
*** 740,741 ****
--- 740,743 ----
{ /* Add new patch number below this line */
+ /**/
+ 371,
/**/
--
hundred-and-one symptoms of being an internet addict:
225. You sign up for free subscriptions for all the computer magazines
/// Bram Moolenaar -- Br...@Moolenaar.net --
http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features --
http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language --
http://www.Zimbu.org ///
\\\ help me help AIDS victims --
http://ICCF-Holland.org ///