]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 8.0.1732: crash when terminal API call deletes the buffer v8.0.1732
authorBram Moolenaar <Bram@vim.org>
Tue, 17 Apr 2018 21:24:06 +0000 (23:24 +0200)
committerBram Moolenaar <Bram@vim.org>
Tue, 17 Apr 2018 21:24:06 +0000 (23:24 +0200)
Problem:    Crash when terminal API call deletes the buffer.
Solution:   Lock the buffer while calling a function. (closes #2813)

src/buffer.c
src/terminal.c
src/testdir/test_autocmd.vim
src/testdir/test_terminal.vim
src/version.c

index 4563736b4d958c962ae2411bcd52839a9f01cc66..c3d3d77b0fa9b0f01335df045256c053862b4f16 100644 (file)
@@ -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
index 9a551a7844f616e4adcca48360b20ab083fcca7f..7f6e48db64741ee7af9703dfe62559c84527d895 100644 (file)
@@ -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
index 61adcae33fd265f96ea12661fe90fcef74bf26ec..2d7956f45d1a3a18b18edc0d215dc2c66b63bbe8 100644 (file)
@@ -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
index 5aa7597e37ec04421190966cff2bc584916eba64..5137659738865943c2db0d83930260fb7c755c30 100644 (file)
@@ -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',
index c3add514465535b37b87dc96ae250f20b97e575d..5647b6e4b2a4c91556c775a56e770d5abdd66982 100644 (file)
@@ -762,6 +762,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1732,
 /**/
     1731,
 /**/