summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <bram@vim.org>2010-07-07 18:20:28 +0200
committerBram Moolenaar <bram@vim.org>2010-07-07 18:20:28 +0200
commit3739afefd83530965aa018c71b78b27b91415797 (patch)
tree82d04f525b3b9d918018c53e5f5be7edd3747b66
parent75b4246bb0a4310424230099bf9f57d2c5191f88 (diff)
downloadvim-3739afefd83530965aa018c71b78b27b91415797.tar.gz
updated for version 7.2.445v7.2.445v7-2-445
Problem: Crash when using undo/redo and a FileChangedRO autocmd event that reloads the buffer. (Dominique Pelle) Solution: Do not allow autocommands while performing and undo or redo.
-rw-r--r--src/misc1.c12
-rw-r--r--src/undo.c41
-rw-r--r--src/version.c2
3 files changed, 49 insertions, 6 deletions
diff --git a/src/misc1.c b/src/misc1.c
index ffd0b831..5482e455 100644
--- a/src/misc1.c
+++ b/src/misc1.c
@@ -2467,10 +2467,12 @@ skip_to_option_part(p)
}
/*
- * changed() is called when something in the current buffer is changed.
+ * Call this function when something in the current buffer is changed.
*
* Most often called through changed_bytes() and changed_lines(), which also
* mark the area of the display to be redrawn.
+ *
+ * Careful: may trigger autocommands that reload the buffer.
*/
void
changed()
@@ -2536,6 +2538,7 @@ static void changed_common __ARGS((linenr_T lnum, colnr_T col, linenr_T lnume, l
* - marks the windows on this buffer to be redisplayed
* - marks the buffer changed by calling changed()
* - invalidates cached values
+ * Careful: may trigger autocommands that reload the buffer.
*/
void
changed_bytes(lnum, col)
@@ -2649,6 +2652,7 @@ deleted_lines_mark(lnum, count)
* below the changed lines (BEFORE the change).
* When only inserting lines, "lnum" and "lnume" are equal.
* Takes care of calling changed() and updating b_mod_*.
+ * Careful: may trigger autocommands that reload the buffer.
*/
void
changed_lines(lnum, col, lnume, xtra)
@@ -2716,6 +2720,11 @@ changed_lines_buf(buf, lnum, lnume, xtra)
}
}
+/*
+ * Common code for when a change is was made.
+ * See changed_lines() for the arguments.
+ * Careful: may trigger autocommands that reload the buffer.
+ */
static void
changed_common(lnum, col, lnume, xtra)
linenr_T lnum;
@@ -2966,6 +2975,7 @@ check_status(buf)
* Don't use emsg(), because it flushes the macro buffer.
* If we have undone all changes b_changed will be FALSE, but "b_did_warn"
* will be TRUE.
+ * Careful: may trigger autocommands that reload the buffer.
*/
void
change_warning(col)
diff --git a/src/undo.c b/src/undo.c
index 39af55b5..0f34af81 100644
--- a/src/undo.c
+++ b/src/undo.c
@@ -185,7 +185,7 @@ u_check_tree(u_header_T *uhp,
}
}
- void
+ static void
u_check(int newhead_may_be_NULL)
{
seen_b_u_newhead = 0;
@@ -320,6 +320,9 @@ undo_allowed()
return TRUE;
}
+/*
+ * Common code for various ways to save text before a change.
+ */
static int
u_savecommon(top, bot, newbot)
linenr_T top, bot;
@@ -374,7 +377,7 @@ u_savecommon(top, bot, newbot)
size = bot - top - 1;
/*
- * if curbuf->b_u_synced == TRUE make a new header
+ * If curbuf->b_u_synced == TRUE make a new header.
*/
if (curbuf->b_u_synced)
{
@@ -709,6 +712,12 @@ u_doit(startcount)
u_oldcount = -1;
while (count--)
{
+ /* Do the change warning now, so that it triggers FileChangedRO when
+ * needed. This may cause the file to be reloaded, that must happen
+ * before we do anything, because it may change curbuf->b_u_curhead
+ * and more. */
+ change_warning(0);
+
if (undo_undoes)
{
if (curbuf->b_u_curhead == NULL) /* first undo */
@@ -952,8 +961,11 @@ undo_time(step, sec, absolute)
/*
* First go up the tree as much as needed.
*/
- for (;;)
+ while (!got_int)
{
+ /* Do the change warning now, for the same reason as above. */
+ change_warning(0);
+
uhp = curbuf->b_u_curhead;
if (uhp == NULL)
uhp = curbuf->b_u_newhead;
@@ -970,9 +982,15 @@ undo_time(step, sec, absolute)
/*
* And now go down the tree (redo), branching off where needed.
*/
- uhp = curbuf->b_u_curhead;
- while (uhp != NULL)
+ while (!got_int)
{
+ /* Do the change warning now, for the same reason as above. */
+ change_warning(0);
+
+ uhp = curbuf->b_u_curhead;
+ if (uhp == NULL)
+ break;
+
/* Go back to the first branch with a mark. */
while (uhp->uh_alt_prev != NULL
&& uhp->uh_alt_prev->uh_walk == mark)
@@ -1070,6 +1088,12 @@ u_undoredo(undo)
int empty_buffer; /* buffer became empty */
u_header_T *curhead = curbuf->b_u_curhead;
+#ifdef FEAT_AUTOCMD
+ /* Don't want autocommands using the undo structures here, they are
+ * invalid till the end. */
+ block_autocmds();
+#endif
+
#ifdef U_DEBUG
u_check(FALSE);
#endif
@@ -1099,6 +1123,9 @@ u_undoredo(undo)
if (top > curbuf->b_ml.ml_line_count || top >= bot
|| bot > curbuf->b_ml.ml_line_count + 1)
{
+#ifdef FEAT_AUTOCMD
+ unblock_autocmds();
+#endif
EMSG(_("E438: u_undo: line numbers wrong"));
changed(); /* don't want UNCHANGED now */
return;
@@ -1304,6 +1331,10 @@ u_undoredo(undo)
/* The timestamp can be the same for multiple changes, just use the one of
* the undone/redone change. */
curbuf->b_u_seq_time = curhead->uh_time;
+
+#ifdef FEAT_AUTOCMD
+ unblock_autocmds();
+#endif
#ifdef U_DEBUG
u_check(FALSE);
#endif
diff --git a/src/version.c b/src/version.c
index c5a029bd..c0096972 100644
--- a/src/version.c
+++ b/src/version.c
@@ -682,6 +682,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 445,
+/**/
444,
/**/
443,