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:
42
src/buffer.c
42
src/buffer.c
@@ -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);
|
||||||
|
|
||||||
|
21
src/misc2.c
21
src/misc2.c
@@ -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);
|
||||||
}
|
}
|
||||||
|
@@ -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,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user