0
0
mirror of https://github.com/vim/vim.git synced 2025-09-25 03:54:15 -04:00

patch 8.1.0342: crash when a callback deletes a window that is being used

Problem:    Crash when a callback deletes a window that is being used.
Solution:   Do not unload a buffer that is being displayed while redrawing the
            screen. Also avoid invoking callbacks while redrawing.
            (closes #2107)
This commit is contained in:
Bram Moolenaar
2018-09-01 15:30:03 +02:00
parent 32bbd00949
commit 94f01956a5
3 changed files with 42 additions and 23 deletions

View File

@@ -412,7 +412,28 @@ buf_hashtab_remove(buf_T *buf)
hash_remove(&buf_hashtab, hi); hash_remove(&buf_hashtab, hi);
} }
static char *e_buflocked = N_("E937: Attempt to delete a buffer that is in use"); /*
* Return TRUE when buffer "buf" can be unloaded.
* Give an error message and return FALSE when the buffer is locked or the
* screen is being redrawn and the buffer is in a window.
*/
static int
can_unload_buffer(buf_T *buf)
{
int can_unload = !buf->b_locked;
if (can_unload && updating_screen)
{
win_T *wp;
FOR_ALL_WINDOWS(wp)
if (wp->w_buffer == buf)
can_unload = FALSE;
}
if (!can_unload)
EMSG(_("E937: Attempt to delete a buffer that is in use"));
return can_unload;
}
/* /*
* Close the link to a buffer. * Close the link to a buffer.
@@ -474,11 +495,9 @@ close_buffer(
{ {
if (wipe_buf || unload_buf) if (wipe_buf || unload_buf)
{ {
if (buf->b_locked) if (!can_unload_buffer(buf))
{
EMSG(_(e_buflocked));
return; return;
}
/* Wiping out or unloading a terminal buffer kills the job. */ /* Wiping out or unloading a terminal buffer kills the job. */
free_terminal(buf); free_terminal(buf);
} }
@@ -501,11 +520,8 @@ close_buffer(
/* Disallow deleting the buffer when it is locked (already being closed or /* Disallow deleting the buffer when it is locked (already being closed or
* halfway a command that relies on it). Unloading is allowed. */ * halfway a command that relies on it). Unloading is allowed. */
if (buf->b_locked > 0 && (del_buf || wipe_buf)) if ((del_buf || wipe_buf) && !can_unload_buffer(buf))
{
EMSG(_(e_buflocked));
return; return;
}
/* check no autocommands closed the window */ /* check no autocommands closed the window */
if (win != NULL && win_valid_any_tab(win)) if (win != NULL && win_valid_any_tab(win))
@@ -1196,8 +1212,6 @@ do_bufdel(
return errormsg; return errormsg;
} }
static int empty_curbuf(int close_others, int forceit, int action);
/* /*
* Make the current buffer empty. * Make the current buffer empty.
* Used when it is wiped out and it's the last buffer. * Used when it is wiped out and it's the last buffer.
@@ -1238,6 +1252,7 @@ empty_curbuf(
need_fileinfo = FALSE; need_fileinfo = FALSE;
return retval; return retval;
} }
/* /*
* Implementation of the commands for the buffer list. * Implementation of the commands for the buffer list.
* *
@@ -1359,11 +1374,8 @@ do_buffer(
int forward; int forward;
bufref_T bufref; bufref_T bufref;
if (buf->b_locked) if (!can_unload_buffer(buf))
{
EMSG(_(e_buflocked));
return FAIL; return FAIL;
}
set_bufref(&bufref, buf); set_bufref(&bufref, buf);

View File

@@ -6366,33 +6366,38 @@ parse_queued_messages(void)
{ {
win_T *old_curwin = curwin; win_T *old_curwin = curwin;
/* For Win32 mch_breakcheck() does not check for input, do it here. */ // Do not handle messages while redrawing, because it may cause buffers to
// change or be wiped while they are being redrawn.
if (updating_screen)
return;
// For Win32 mch_breakcheck() does not check for input, do it here.
# if defined(WIN32) && defined(FEAT_JOB_CHANNEL) # if defined(WIN32) && defined(FEAT_JOB_CHANNEL)
channel_handle_events(FALSE); channel_handle_events(FALSE);
# endif # endif
# ifdef FEAT_NETBEANS_INTG # ifdef FEAT_NETBEANS_INTG
/* Process the queued netbeans messages. */ // Process the queued netbeans messages.
netbeans_parse_messages(); netbeans_parse_messages();
# endif # endif
# ifdef FEAT_JOB_CHANNEL # ifdef FEAT_JOB_CHANNEL
/* Write any buffer lines still to be written. */ // Write any buffer lines still to be written.
channel_write_any_lines(); channel_write_any_lines();
/* Process the messages queued on channels. */ // Process the messages queued on channels.
channel_parse_messages(); channel_parse_messages();
# endif # endif
# if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11) # if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
/* Process the queued clientserver messages. */ // Process the queued clientserver messages.
server_parse_messages(); server_parse_messages();
# endif # endif
# ifdef FEAT_JOB_CHANNEL # ifdef FEAT_JOB_CHANNEL
/* Check if any jobs have ended. */ // Check if any jobs have ended.
job_check_ended(); job_check_ended();
# endif # endif
/* If the current window changed we need to bail out of the waiting loop. // If the current window changed we need to bail out of the waiting loop.
* E.g. when a job exit callback closes the terminal window. */ // E.g. when a job exit callback closes the terminal window.
if (curwin != old_curwin) if (curwin != old_curwin)
ins_char_typebuf(K_IGNORE); ins_char_typebuf(K_IGNORE);
} }

View File

@@ -794,6 +794,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
342,
/**/ /**/
341, 341,
/**/ /**/