changeset 5586:505cf1943dc2 v7.4.140

updated for version 7.4.140 Problem: Crash when wiping out buffer triggers autocommand that wipes out only other buffer. Solution: Do not delete the last buffer, make it empty. (Hirohito Higashi)
author Bram Moolenaar <bram@vim.org>
date Fri, 10 Jan 2014 16:43:14 +0100
parents 8ce54730f806
children 3fd0adcb6941
files src/buffer.c src/version.c
diffstat 2 files changed, 56 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -994,6 +994,50 @@ do_bufdel(command, arg, addr_count, star
 #if defined(FEAT_LISTCMDS) || defined(FEAT_PYTHON) \
 	|| defined(FEAT_PYTHON3) || defined(PROTO)
 
+static int	empty_curbuf __ARGS((int close_others, int forceit, int action));
+
+/*
+ * Make the current buffer empty.
+ * Used when it is wiped out and it's the last buffer.
+ */
+    static int
+empty_curbuf(close_others, forceit, action)
+    int close_others;
+    int forceit;
+    int action;
+{
+    int	    retval;
+    buf_T   *buf = curbuf;
+
+    if (action == DOBUF_UNLOAD)
+    {
+	EMSG(_("E90: Cannot unload last buffer"));
+	return FAIL;
+    }
+
+    if (close_others)
+    {
+	/* Close any other windows on this buffer, then make it empty. */
+#ifdef FEAT_WINDOWS
+	close_windows(buf, TRUE);
+#endif
+    }
+
+    setpcmark();
+    retval = do_ecmd(0, NULL, NULL, NULL, ECMD_ONE,
+					  forceit ? ECMD_FORCEIT : 0, curwin);
+
+    /*
+     * do_ecmd() may create a new buffer, then we have to delete
+     * the old one.  But do_ecmd() may have done that already, check
+     * if the buffer still exists.
+     */
+    if (buf != curbuf && buf_valid(buf) && buf->b_nwindows == 0)
+	close_buffer(NULL, buf, action, FALSE);
+    if (!close_others)
+	need_fileinfo = FALSE;
+    return retval;
+}
 /*
  * Implementation of the commands for the buffer list.
  *
@@ -1114,7 +1158,6 @@ do_buffer(action, start, dir, count, for
     if (unload)
     {
 	int	forward;
-	int	retval;
 
 	/* When unloading or deleting a buffer that's already unloaded and
 	 * unlisted: fail silently. */
@@ -1155,30 +1198,7 @@ do_buffer(action, start, dir, count, for
 	    if (bp->b_p_bl && bp != buf)
 		break;
 	if (bp == NULL && buf == curbuf)
-	{
-	    if (action == DOBUF_UNLOAD)
-	    {
-		EMSG(_("E90: Cannot unload last buffer"));
-		return FAIL;
-	    }
-
-	    /* Close any other windows on this buffer, then make it empty. */
-#ifdef FEAT_WINDOWS
-	    close_windows(buf, TRUE);
-#endif
-	    setpcmark();
-	    retval = do_ecmd(0, NULL, NULL, NULL, ECMD_ONE,
-					  forceit ? ECMD_FORCEIT : 0, curwin);
-
-	    /*
-	     * do_ecmd() may create a new buffer, then we have to delete
-	     * the old one.  But do_ecmd() may have done that already, check
-	     * if the buffer still exists.
-	     */
-	    if (buf != curbuf && buf_valid(buf) && buf->b_nwindows == 0)
-		close_buffer(NULL, buf, action, FALSE);
-	    return retval;
-	}
+	    return empty_curbuf(TRUE, forceit, action);
 
 #ifdef FEAT_WINDOWS
 	/*
@@ -1212,7 +1232,8 @@ do_buffer(action, start, dir, count, for
 
 	/*
 	 * Deleting the current buffer: Need to find another buffer to go to.
-	 * There must be another, otherwise it would have been handled above.
+	 * There should be another, otherwise it would have been handled
+	 * above.  However, autocommands may have deleted all buffers.
 	 * First use au_new_curbuf, if it is valid.
 	 * Then prefer the buffer we most recently visited.
 	 * Else try to find one that is loaded, after the current buffer,
@@ -1311,6 +1332,13 @@ do_buffer(action, start, dir, count, for
 	}
     }
 
+    if (buf == NULL)
+    {
+	/* Autocommands must have wiped out all other buffers.  Only option
+	 * now is to make the current buffer empty. */
+	return empty_curbuf(FALSE, forceit, action);
+    }
+
     /*
      * make buf current buffer
      */
--- a/src/version.c
+++ b/src/version.c
@@ -739,6 +739,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    140,
+/**/
     139,
 /**/
     138,