summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2018-04-17 23:24:06 +0200
committerBram Moolenaar <Bram@vim.org>2018-04-17 23:24:06 +0200
commita997b45c7e350ea5b378ca0c52ed3d4cc610975c (patch)
tree4ce7c2e8741723990ad32cea475b013215a250e8
parente87edf3b85f607632e5431640071fdbc36b685b2 (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.c17
-rw-r--r--src/terminal.c8
-rw-r--r--src/testdir/test_autocmd.vim11
-rw-r--r--src/testdir/test_terminal.vim24
-rw-r--r--src/version.c2
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,