diff options
author | Bram Moolenaar <Bram@vim.org> | 2018-04-17 23:24:06 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2018-04-17 23:24:06 +0200 |
commit | a997b45c7e350ea5b378ca0c52ed3d4cc610975c (patch) | |
tree | 4ce7c2e8741723990ad32cea475b013215a250e8 | |
parent | e87edf3b85f607632e5431640071fdbc36b685b2 (diff) |
patch 8.0.1732: crash when terminal API call deletes the bufferv8.0.1732
Problem: Crash when terminal API call deletes the buffer.
Solution: Lock the buffer while calling a function. (closes #2813)
-rw-r--r-- | src/buffer.c | 17 | ||||
-rw-r--r-- | src/terminal.c | 8 | ||||
-rw-r--r-- | src/testdir/test_autocmd.vim | 11 | ||||
-rw-r--r-- | src/testdir/test_terminal.vim | 24 | ||||
-rw-r--r-- | src/version.c | 2 |
5 files changed, 57 insertions, 5 deletions
diff --git a/src/buffer.c b/src/buffer.c index 4563736b4d..c3d3d77b0f 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -417,6 +417,8 @@ buf_hashtab_remove(buf_T *buf) hash_remove(&buf_hashtab, hi); } +static char *e_buflocked = N_("E937: Attempt to delete a buffer that is in use"); + /* * Close the link to a buffer. * "action" is used when there is no longer a window for the buffer. @@ -476,8 +478,15 @@ close_buffer( if (term_job_running(buf->b_term)) { if (wipe_buf || unload_buf) + { + if (buf->b_locked) + { + EMSG(_(e_buflocked)); + return; + } /* Wiping out or unloading a terminal buffer kills the job. */ free_terminal(buf); + } else { /* The job keeps running, hide the buffer. */ @@ -499,7 +508,7 @@ close_buffer( * halfway a command that relies on it). Unloading is allowed. */ if (buf->b_locked > 0 && (del_buf || wipe_buf)) { - EMSG(_("E937: Attempt to delete a buffer that is in use")); + EMSG(_(e_buflocked)); return; } @@ -1356,6 +1365,12 @@ do_buffer( int forward; bufref_T bufref; + if (buf->b_locked) + { + EMSG(_(e_buflocked)); + return FAIL; + } + set_bufref(&bufref, buf); /* When unloading or deleting a buffer that's already unloaded and diff --git a/src/terminal.c b/src/terminal.c index 9a551a7844..7f6e48db64 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -46,6 +46,9 @@ * switch to GUI, shell stops working. Scrollback seems wrong, command * running in shell is still running. * - GUI: when using tabs, focus in terminal, click on tab does not work. + * - handle_moverect() scrolls one line at a time. Postpone scrolling, count + * the number of lines, until a redraw happens. Then if scrolling many lines + * a redraw is faster. * - Copy text in the vterm to the Vim buffer once in a while, so that * completion works. * - Redrawing is slow with Athena and Motif. Also other GUI? (Ramel Eshed) @@ -3433,6 +3436,10 @@ parse_osc(const char *command, size_t cmdlen, void *user) { char_u *cmd = get_tv_string(&item->li_tv); + /* Make sure an invoked command doesn't delete the buffer (and the + * terminal) under our fingers. */ + ++term->tl_buffer->b_locked; + item = item->li_next; if (item == NULL) ch_log(channel, "Missing argument for %s", cmd); @@ -3442,6 +3449,7 @@ parse_osc(const char *command, size_t cmdlen, void *user) handle_call_command(term, channel, item); else ch_log(channel, "Invalid command received: %s", cmd); + --term->tl_buffer->b_locked; } } else diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim index 61adcae33f..2d7956f45d 100644 --- a/src/testdir/test_autocmd.vim +++ b/src/testdir/test_autocmd.vim @@ -119,7 +119,9 @@ func Test_autocmd_bufunload_avoiding_SEGV_01() exe 'autocmd BufUnload <buffer> ' . (lastbuf + 1) . 'bwipeout!' augroup END - call assert_fails('edit bb.txt', 'E937:') + " Todo: check for E937 generated first + " call assert_fails('edit bb.txt', 'E937:') + call assert_fails('edit bb.txt', 'E517:') autocmd! test_autocmd_bufunload augroup! test_autocmd_bufunload @@ -316,7 +318,7 @@ func Test_three_windows() e Xtestje2 sp Xtestje1 call assert_fails('e', 'E937:') - call assert_equal('Xtestje2', expand('%')) + call assert_equal('Xtestje1', expand('%')) " Test changing buffers in a BufWipeout autocommand. If this goes wrong " there are ml_line errors and/or a Crash. @@ -338,7 +340,6 @@ func Test_three_windows() au! enew - bwipe! Xtestje1 call delete('Xtestje1') call delete('Xtestje2') call delete('Xtestje3') @@ -1181,7 +1182,9 @@ endfunc func Test_nocatch_wipe_all_buffers() " Real nasty autocommand: wipe all buffers on any event. au * * bwipe * - call assert_fails('next x', 'E93') + " Get E93 first? + " call assert_fails('next x', 'E93:') + call assert_fails('next x', 'E517:') bwipe au! endfunc diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index 5aa7597e37..5137659738 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -1287,6 +1287,30 @@ func Test_terminal_api_call_fails() call delete('Xlog') endfunc +let s:caught_e937 = 0 + +func Tapi_Delete(bufnum, arg) + try + execute 'bdelete!' a:bufnum + catch /E937:/ + let s:caught_e937 = 1 + endtry +endfunc + +func Test_terminal_api_call_fail_delete() + if !CanRunVimInTerminal() + return + endif + + call WriteApiCall('Tapi_Delete') + let buf = RunVimInTerminal('-S Xscript', {}) + call WaitFor({-> s:caught_e937 == 1}) + + call StopVimInTerminal(buf) + call delete('Xscript') + call ch_logfile('', '') +endfunc + func Test_terminal_ansicolors_default() let colors = [ \ '#000000', '#e00000', diff --git a/src/version.c b/src/version.c index c3add51446..5647b6e4b2 100644 --- a/src/version.c +++ b/src/version.c @@ -763,6 +763,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1732, +/**/ 1731, /**/ 1730, |