# HG changeset patch # User Christian Brabandt # Date 1502626503 -7200 # Node ID 69f2392e6cfbede15ad392b07a0177af97224418 # Parent 1d822821df72914c2584351c3dd01036504a093f patch 8.0.0923: crash in GUI when terminal job exits commit https://github.com/vim/vim/commit/679653e59c6da7f6abc29470ef9d404582bacbb9 Author: Bram Moolenaar 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. diff --git a/src/terminal.c b/src/terminal.c --- 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) diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim --- 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 diff --git a/src/version.c b/src/version.c --- 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,