changeset 12086:69f2392e6cfb v8.0.0923

patch 8.0.0923: crash in GUI when terminal job exits commit https://github.com/vim/vim/commit/679653e59c6da7f6abc29470ef9d404582bacbb9 Author: Bram Moolenaar <Bram@vim.org> Date: Sun Aug 13 14:13:19 2017 +0200 patch 8.0.0923: crash in GUI when terminal job exits Problem: Crash in GUI when terminal job exits. (Kazunobu Kuriyama) Solution: reset in_terminal_loop when a terminal is freed.
author Christian Brabandt <cb@256bit.org>
date Sun, 13 Aug 2017 14:15:03 +0200
parents 1d822821df72
children 76c7a8c1ce69
files src/terminal.c src/testdir/test_terminal.vim src/version.c
diffstat 3 files changed, 38 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -34,9 +34,10 @@
  *
  * When the job ends the text is put in a buffer.  Redrawing then happens from
  * that buffer, attributes come from the scrollback buffer tl_scrollback.
+ * When the buffer is changed it is turned into a normal buffer, the attributes
+ * in tl_scrollback are no longer used.
  *
  * TODO:
- * - cursor shape/color/blink in the GUI
  * - Make argument list work on MS-Windows. #1954
  * - MS-Windows: no redraw for 'updatetime'  #1915
  * - To set BS correctly, check get_stty(); Pass the fd of the pty.
@@ -524,6 +525,8 @@ free_terminal(buf_T *buf)
     vim_free(term->tl_cursor_color);
     vim_free(term);
     buf->b_term = NULL;
+    if (in_terminal_loop == term)
+	in_terminal_loop = NULL;
 }
 
 /*
@@ -1014,6 +1017,8 @@ term_enter_job_mode()
 
 /*
  * Get a key from the user without mapping.
+ * Note: while waiting a terminal may be closed and freed if the channel is
+ * closed and ++close was used.
  * TODO: use terminal mode mappings.
  */
     static int
@@ -1140,10 +1145,16 @@ term_paste_register(int prev_c UNUSED)
 #ifdef FEAT_CMDL_INFO
     clear_showcmd();
 #endif
+    if (!term_use_loop())
+	/* job finished while waiting for a character */
+	return;
 
     /* CTRL-W "= prompt for expression to evaluate. */
     if (c == '=' && get_expr_register() != '=')
 	return;
+    if (!term_use_loop())
+	/* job finished while waiting for a character */
+	return;
 
     l = (list_T *)get_reg_contents(c, GREG_LIST);
     if (l != NULL)
@@ -1272,6 +1283,10 @@ terminal_loop(void)
     int		termkey = 0;
     int		ret;
 
+    /* Remember the terminal we are sending keys to.  However, the terminal
+     * might be closed while waiting for a character, e.g. typing "exit" in a
+     * shell and ++close was used.  Therefore use curbuf->b_term instead of a
+     * stored reference. */
     in_terminal_loop = curbuf->b_term;
 
     if (*curwin->w_p_tk != NUL)
--- a/src/testdir/test_terminal.vim
+++ b/src/testdir/test_terminal.vim
@@ -414,3 +414,23 @@ func Test_terminal_env()
 
   exe buf . 'bwipe'
 endfunc
+
+" must be last, we can't go back from GUI to terminal
+func Test_zz_terminal_in_gui()
+  if !has('gui')
+    return
+  endif
+  gui -f
+
+  call assert_equal(1, winnr('$'))
+  let buf = Run_shell_in_terminal({'term_finish': 'close'})
+  call Stop_shell_in_terminal(buf)
+  call term_wait(buf)
+
+  " closing window wipes out the terminal buffer a with finished job
+  call WaitFor("winnr('$') == 1")
+  call assert_equal(1, winnr('$'))
+  call assert_equal("", bufname(buf))
+
+  unlet g:job
+endfunc
--- a/src/version.c
+++ b/src/version.c
@@ -770,6 +770,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    923,
+/**/
     922,
 /**/
     921,