Karsten Hopp eaec1b
To: vim-dev@vim.org
Karsten Hopp eaec1b
Subject: About patch 7.1.130
Karsten Hopp eaec1b
Fcc: outbox
Karsten Hopp eaec1b
From: Bram Moolenaar <Bram@moolenaar.net>
Karsten Hopp eaec1b
Mime-Version: 1.0
Karsten Hopp eaec1b
Content-Type: text/plain; charset=ISO-8859-1
Karsten Hopp eaec1b
Content-Transfer-Encoding: 8bit
Karsten Hopp eaec1b
------------
Karsten Hopp eaec1b
Karsten Hopp eaec1b
Patch 7.1.130
Karsten Hopp eaec1b
Problem:    Crash with specific order of undo and redo. (A.Politz)
Karsten Hopp eaec1b
Solution:   Clear and adjust pointers properly.  Add u_check() for debugging.
Karsten Hopp eaec1b
Files:	    src/undo.c, src/structs.h
Karsten Hopp eaec1b
Karsten Hopp eaec1b
Karsten Hopp eaec1b
*** ../vim-7.1.129/src/undo.c	Thu May 10 20:01:43 2007
Karsten Hopp eaec1b
--- src/undo.c	Mon Oct  1 22:49:16 2007
Karsten Hopp eaec1b
***************
Karsten Hopp eaec1b
*** 76,81 ****
Karsten Hopp eaec1b
--- 76,87 ----
Karsten Hopp eaec1b
   * buffer is unloaded.
Karsten Hopp eaec1b
   */
Karsten Hopp eaec1b
  
Karsten Hopp eaec1b
+ /* Uncomment the next line for including the u_check() function.  This warns
Karsten Hopp eaec1b
+  * for errors in the debug information. */
Karsten Hopp eaec1b
+ /* #define U_DEBUG 1 */
Karsten Hopp eaec1b
+ #define UH_MAGIC 0x18dade	/* value for uh_magic when in use */
Karsten Hopp eaec1b
+ #define UE_MAGIC 0xabc123	/* value for ue_magic when in use */
Karsten Hopp eaec1b
+ 
Karsten Hopp eaec1b
  #include "vim.h"
Karsten Hopp eaec1b
  
Karsten Hopp eaec1b
  /* See below: use malloc()/free() for memory management. */
Karsten Hopp eaec1b
***************
Karsten Hopp eaec1b
*** 113,118 ****
Karsten Hopp eaec1b
--- 119,213 ----
Karsten Hopp eaec1b
   */
Karsten Hopp eaec1b
  static int	undo_undoes = FALSE;
Karsten Hopp eaec1b
  
Karsten Hopp eaec1b
+ #ifdef U_DEBUG
Karsten Hopp eaec1b
+ /*
Karsten Hopp eaec1b
+  * Check the undo structures for being valid.  Print a warning when something
Karsten Hopp eaec1b
+  * looks wrong.
Karsten Hopp eaec1b
+  */
Karsten Hopp eaec1b
+ static int seen_b_u_curhead;
Karsten Hopp eaec1b
+ static int seen_b_u_newhead;
Karsten Hopp eaec1b
+ static int header_count;
Karsten Hopp eaec1b
+ 
Karsten Hopp eaec1b
+     static void
Karsten Hopp eaec1b
+ u_check_tree(u_header_T *uhp,
Karsten Hopp eaec1b
+ 	u_header_T *exp_uh_next,
Karsten Hopp eaec1b
+ 	u_header_T *exp_uh_alt_prev)
Karsten Hopp eaec1b
+ {
Karsten Hopp eaec1b
+     u_entry_T *uep;
Karsten Hopp eaec1b
+ 
Karsten Hopp eaec1b
+     if (uhp == NULL)
Karsten Hopp eaec1b
+ 	return;
Karsten Hopp eaec1b
+     ++header_count;
Karsten Hopp eaec1b
+     if (uhp == curbuf->b_u_curhead && ++seen_b_u_curhead > 1)
Karsten Hopp eaec1b
+     {
Karsten Hopp eaec1b
+ 	EMSG("b_u_curhead found twice (looping?)");
Karsten Hopp eaec1b
+ 	return;
Karsten Hopp eaec1b
+     }
Karsten Hopp eaec1b
+     if (uhp == curbuf->b_u_newhead && ++seen_b_u_newhead > 1)
Karsten Hopp eaec1b
+     {
Karsten Hopp eaec1b
+ 	EMSG("b_u_newhead found twice (looping?)");
Karsten Hopp eaec1b
+ 	return;
Karsten Hopp eaec1b
+     }
Karsten Hopp eaec1b
+ 
Karsten Hopp eaec1b
+     if (uhp->uh_magic != UH_MAGIC)
Karsten Hopp eaec1b
+ 	EMSG("uh_magic wrong (may be using freed memory)");
Karsten Hopp eaec1b
+     else
Karsten Hopp eaec1b
+     {
Karsten Hopp eaec1b
+ 	/* Check pointers back are correct. */
Karsten Hopp eaec1b
+ 	if (uhp->uh_next != exp_uh_next)
Karsten Hopp eaec1b
+ 	{
Karsten Hopp eaec1b
+ 	    EMSG("uh_next wrong");
Karsten Hopp eaec1b
+ 	    smsg((char_u *)"expected: 0x%x, actual: 0x%x",
Karsten Hopp eaec1b
+ 						   exp_uh_next, uhp->uh_next);
Karsten Hopp eaec1b
+ 	}
Karsten Hopp eaec1b
+ 	if (uhp->uh_alt_prev != exp_uh_alt_prev)
Karsten Hopp eaec1b
+ 	{
Karsten Hopp eaec1b
+ 	    EMSG("uh_alt_prev wrong");
Karsten Hopp eaec1b
+ 	    smsg((char_u *)"expected: 0x%x, actual: 0x%x",
Karsten Hopp eaec1b
+ 					   exp_uh_alt_prev, uhp->uh_alt_prev);
Karsten Hopp eaec1b
+ 	}
Karsten Hopp eaec1b
+ 
Karsten Hopp eaec1b
+ 	/* Check the undo tree at this header. */
Karsten Hopp eaec1b
+ 	for (uep = uhp->uh_entry; uep != NULL; uep = uep->ue_next)
Karsten Hopp eaec1b
+ 	{
Karsten Hopp eaec1b
+ 	    if (uep->ue_magic != UE_MAGIC)
Karsten Hopp eaec1b
+ 	    {
Karsten Hopp eaec1b
+ 		EMSG("ue_magic wrong (may be using freed memory)");
Karsten Hopp eaec1b
+ 		break;
Karsten Hopp eaec1b
+ 	    }
Karsten Hopp eaec1b
+ 	}
Karsten Hopp eaec1b
+ 
Karsten Hopp eaec1b
+ 	/* Check the next alt tree. */
Karsten Hopp eaec1b
+ 	u_check_tree(uhp->uh_alt_next, uhp->uh_next, uhp);
Karsten Hopp eaec1b
+ 
Karsten Hopp eaec1b
+ 	/* Check the next header in this branch. */
Karsten Hopp eaec1b
+ 	u_check_tree(uhp->uh_prev, uhp, NULL);
Karsten Hopp eaec1b
+     }
Karsten Hopp eaec1b
+ }
Karsten Hopp eaec1b
+ 
Karsten Hopp eaec1b
+     void
Karsten Hopp eaec1b
+ u_check(int newhead_may_be_NULL)
Karsten Hopp eaec1b
+ {
Karsten Hopp eaec1b
+     seen_b_u_newhead = 0;
Karsten Hopp eaec1b
+     seen_b_u_curhead = 0;
Karsten Hopp eaec1b
+     header_count = 0;
Karsten Hopp eaec1b
+ 
Karsten Hopp eaec1b
+     u_check_tree(curbuf->b_u_oldhead, NULL, NULL);
Karsten Hopp eaec1b
+ 
Karsten Hopp eaec1b
+     if (seen_b_u_newhead == 0 && curbuf->b_u_oldhead != NULL
Karsten Hopp eaec1b
+ 	    && !(newhead_may_be_NULL && curbuf->b_u_newhead == NULL))
Karsten Hopp eaec1b
+ 	EMSGN("b_u_newhead invalid: 0x%x", curbuf->b_u_newhead);
Karsten Hopp eaec1b
+     if (curbuf->b_u_curhead != NULL && seen_b_u_curhead == 0)
Karsten Hopp eaec1b
+ 	EMSGN("b_u_curhead invalid: 0x%x", curbuf->b_u_curhead);
Karsten Hopp eaec1b
+     if (header_count != curbuf->b_u_numhead)
Karsten Hopp eaec1b
+     {
Karsten Hopp eaec1b
+ 	EMSG("b_u_numhead invalid");
Karsten Hopp eaec1b
+ 	smsg((char_u *)"expected: %ld, actual: %ld",
Karsten Hopp eaec1b
+ 			       (long)header_count, (long)curbuf->b_u_numhead);
Karsten Hopp eaec1b
+     }
Karsten Hopp eaec1b
+ }
Karsten Hopp eaec1b
+ #endif
Karsten Hopp eaec1b
+ 
Karsten Hopp eaec1b
  /*
Karsten Hopp eaec1b
   * Save the current line for both the "u" and "U" command.
Karsten Hopp eaec1b
   * Returns OK or FAIL.
Karsten Hopp eaec1b
***************
Karsten Hopp eaec1b
*** 243,248 ****
Karsten Hopp eaec1b
--- 338,346 ----
Karsten Hopp eaec1b
      if (!undo_allowed())
Karsten Hopp eaec1b
  	return FAIL;
Karsten Hopp eaec1b
  
Karsten Hopp eaec1b
+ #ifdef U_DEBUG
Karsten Hopp eaec1b
+     u_check(FALSE);
Karsten Hopp eaec1b
+ #endif
Karsten Hopp eaec1b
  #ifdef FEAT_NETBEANS_INTG
Karsten Hopp eaec1b
      /*
Karsten Hopp eaec1b
       * Netbeans defines areas that cannot be modified.  Bail out here when
Karsten Hopp eaec1b
***************
Karsten Hopp eaec1b
*** 294,299 ****
Karsten Hopp eaec1b
--- 392,400 ----
Karsten Hopp eaec1b
  	    uhp = (u_header_T *)U_ALLOC_LINE((unsigned)sizeof(u_header_T));
Karsten Hopp eaec1b
  	    if (uhp == NULL)
Karsten Hopp eaec1b
  		goto nomem;
Karsten Hopp eaec1b
+ #ifdef U_DEBUG
Karsten Hopp eaec1b
+ 	    uhp->uh_magic = UH_MAGIC;
Karsten Hopp eaec1b
+ #endif
Karsten Hopp eaec1b
  	}
Karsten Hopp eaec1b
  	else
Karsten Hopp eaec1b
  	    uhp = NULL;
Karsten Hopp eaec1b
***************
Karsten Hopp eaec1b
*** 316,323 ****
Karsten Hopp eaec1b
  	{
Karsten Hopp eaec1b
  	    u_header_T	    *uhfree = curbuf->b_u_oldhead;
Karsten Hopp eaec1b
  
Karsten Hopp eaec1b
! 	    /* If there is no branch only free one header. */
Karsten Hopp eaec1b
! 	    if (uhfree->uh_alt_next == NULL)
Karsten Hopp eaec1b
  		u_freeheader(curbuf, uhfree, &old_curhead);
Karsten Hopp eaec1b
  	    else
Karsten Hopp eaec1b
  	    {
Karsten Hopp eaec1b
--- 417,427 ----
Karsten Hopp eaec1b
  	{
Karsten Hopp eaec1b
  	    u_header_T	    *uhfree = curbuf->b_u_oldhead;
Karsten Hopp eaec1b
  
Karsten Hopp eaec1b
! 	    if (uhfree == old_curhead)
Karsten Hopp eaec1b
! 		/* Can't reconnect the branch, delete all of it. */
Karsten Hopp eaec1b
! 		u_freebranch(curbuf, uhfree, &old_curhead);
Karsten Hopp eaec1b
! 	    else if (uhfree->uh_alt_next == NULL)
Karsten Hopp eaec1b
! 		/* There is no branch, only free one header. */
Karsten Hopp eaec1b
  		u_freeheader(curbuf, uhfree, &old_curhead);
Karsten Hopp eaec1b
  	    else
Karsten Hopp eaec1b
  	    {
Karsten Hopp eaec1b
***************
Karsten Hopp eaec1b
*** 326,331 ****
Karsten Hopp eaec1b
--- 430,438 ----
Karsten Hopp eaec1b
  		    uhfree = uhfree->uh_alt_next;
Karsten Hopp eaec1b
  		u_freebranch(curbuf, uhfree, &old_curhead);
Karsten Hopp eaec1b
  	    }
Karsten Hopp eaec1b
+ #ifdef U_DEBUG
Karsten Hopp eaec1b
+ 	    u_check(TRUE);
Karsten Hopp eaec1b
+ #endif
Karsten Hopp eaec1b
  	}
Karsten Hopp eaec1b
  
Karsten Hopp eaec1b
  	if (uhp == NULL)		/* no undo at all */
Karsten Hopp eaec1b
***************
Karsten Hopp eaec1b
*** 478,483 ****
Karsten Hopp eaec1b
--- 585,593 ----
Karsten Hopp eaec1b
      uep = (u_entry_T *)U_ALLOC_LINE((unsigned)sizeof(u_entry_T));
Karsten Hopp eaec1b
      if (uep == NULL)
Karsten Hopp eaec1b
  	goto nomem;
Karsten Hopp eaec1b
+ #ifdef U_DEBUG
Karsten Hopp eaec1b
+     uep->ue_magic = UE_MAGIC;
Karsten Hopp eaec1b
+ #endif
Karsten Hopp eaec1b
  
Karsten Hopp eaec1b
      uep->ue_size = size;
Karsten Hopp eaec1b
      uep->ue_top = top;
Karsten Hopp eaec1b
***************
Karsten Hopp eaec1b
*** 525,530 ****
Karsten Hopp eaec1b
--- 635,643 ----
Karsten Hopp eaec1b
      curbuf->b_u_synced = FALSE;
Karsten Hopp eaec1b
      undo_undoes = FALSE;
Karsten Hopp eaec1b
  
Karsten Hopp eaec1b
+ #ifdef U_DEBUG
Karsten Hopp eaec1b
+     u_check(FALSE);
Karsten Hopp eaec1b
+ #endif
Karsten Hopp eaec1b
      return OK;
Karsten Hopp eaec1b
  
Karsten Hopp eaec1b
  nomem:
Karsten Hopp eaec1b
***************
Karsten Hopp eaec1b
*** 955,960 ****
Karsten Hopp eaec1b
--- 1068,1076 ----
Karsten Hopp eaec1b
      int		empty_buffer;		    /* buffer became empty */
Karsten Hopp eaec1b
      u_header_T	*curhead = curbuf->b_u_curhead;
Karsten Hopp eaec1b
  
Karsten Hopp eaec1b
+ #ifdef U_DEBUG
Karsten Hopp eaec1b
+     u_check(FALSE);
Karsten Hopp eaec1b
+ #endif
Karsten Hopp eaec1b
      old_flags = curhead->uh_flags;
Karsten Hopp eaec1b
      new_flags = (curbuf->b_changed ? UH_CHANGED : 0) +
Karsten Hopp eaec1b
  	       ((curbuf->b_ml.ml_flags & ML_EMPTY) ? UH_EMPTYBUF : 0);
Karsten Hopp eaec1b
***************
Karsten Hopp eaec1b
*** 1186,1191 ****
Karsten Hopp eaec1b
--- 1302,1310 ----
Karsten Hopp eaec1b
      /* The timestamp can be the same for multiple changes, just use the one of
Karsten Hopp eaec1b
       * the undone/redone change. */
Karsten Hopp eaec1b
      curbuf->b_u_seq_time = curhead->uh_time;
Karsten Hopp eaec1b
+ #ifdef U_DEBUG
Karsten Hopp eaec1b
+     u_check(FALSE);
Karsten Hopp eaec1b
+ #endif
Karsten Hopp eaec1b
  }
Karsten Hopp eaec1b
  
Karsten Hopp eaec1b
  /*
Karsten Hopp eaec1b
***************
Karsten Hopp eaec1b
*** 1515,1521 ****
Karsten Hopp eaec1b
  }
Karsten Hopp eaec1b
  
Karsten Hopp eaec1b
  /*
Karsten Hopp eaec1b
!  * Free one header and its entry list and adjust the pointers.
Karsten Hopp eaec1b
   */
Karsten Hopp eaec1b
      static void
Karsten Hopp eaec1b
  u_freeheader(buf, uhp, uhpp)
Karsten Hopp eaec1b
--- 1634,1640 ----
Karsten Hopp eaec1b
  }
Karsten Hopp eaec1b
  
Karsten Hopp eaec1b
  /*
Karsten Hopp eaec1b
!  * Free one header "uhp" and its entry list and adjust the pointers.
Karsten Hopp eaec1b
   */
Karsten Hopp eaec1b
      static void
Karsten Hopp eaec1b
  u_freeheader(buf, uhp, uhpp)
Karsten Hopp eaec1b
***************
Karsten Hopp eaec1b
*** 1523,1528 ****
Karsten Hopp eaec1b
--- 1642,1649 ----
Karsten Hopp eaec1b
      u_header_T	    *uhp;
Karsten Hopp eaec1b
      u_header_T	    **uhpp;	/* if not NULL reset when freeing this header */
Karsten Hopp eaec1b
  {
Karsten Hopp eaec1b
+     u_header_T	    *uhap;
Karsten Hopp eaec1b
+ 
Karsten Hopp eaec1b
      /* When there is an alternate redo list free that branch completely,
Karsten Hopp eaec1b
       * because we can never go there. */
Karsten Hopp eaec1b
      if (uhp->uh_alt_next != NULL)
Karsten Hopp eaec1b
***************
Karsten Hopp eaec1b
*** 1540,1546 ****
Karsten Hopp eaec1b
      if (uhp->uh_prev == NULL)
Karsten Hopp eaec1b
  	buf->b_u_newhead = uhp->uh_next;
Karsten Hopp eaec1b
      else
Karsten Hopp eaec1b
! 	uhp->uh_prev->uh_next = uhp->uh_next;
Karsten Hopp eaec1b
  
Karsten Hopp eaec1b
      u_freeentries(buf, uhp, uhpp);
Karsten Hopp eaec1b
  }
Karsten Hopp eaec1b
--- 1661,1668 ----
Karsten Hopp eaec1b
      if (uhp->uh_prev == NULL)
Karsten Hopp eaec1b
  	buf->b_u_newhead = uhp->uh_next;
Karsten Hopp eaec1b
      else
Karsten Hopp eaec1b
! 	for (uhap = uhp->uh_prev; uhap != NULL; uhap = uhap->uh_alt_next)
Karsten Hopp eaec1b
! 	    uhap->uh_next = uhp->uh_next;
Karsten Hopp eaec1b
  
Karsten Hopp eaec1b
      u_freeentries(buf, uhp, uhpp);
Karsten Hopp eaec1b
  }
Karsten Hopp eaec1b
***************
Karsten Hopp eaec1b
*** 1585,1590 ****
Karsten Hopp eaec1b
--- 1707,1714 ----
Karsten Hopp eaec1b
      /* Check for pointers to the header that become invalid now. */
Karsten Hopp eaec1b
      if (buf->b_u_curhead == uhp)
Karsten Hopp eaec1b
  	buf->b_u_curhead = NULL;
Karsten Hopp eaec1b
+     if (buf->b_u_newhead == uhp)
Karsten Hopp eaec1b
+ 	buf->b_u_newhead = NULL;  /* freeing the newest entry */
Karsten Hopp eaec1b
      if (uhpp != NULL && uhp == *uhpp)
Karsten Hopp eaec1b
  	*uhpp = NULL;
Karsten Hopp eaec1b
  
Karsten Hopp eaec1b
***************
Karsten Hopp eaec1b
*** 1594,1599 ****
Karsten Hopp eaec1b
--- 1718,1726 ----
Karsten Hopp eaec1b
  	u_freeentry(uep, uep->ue_size);
Karsten Hopp eaec1b
      }
Karsten Hopp eaec1b
  
Karsten Hopp eaec1b
+ #ifdef U_DEBUG
Karsten Hopp eaec1b
+     uhp->uh_magic = 0;
Karsten Hopp eaec1b
+ #endif
Karsten Hopp eaec1b
      U_FREE_LINE((char_u *)uhp);
Karsten Hopp eaec1b
      --buf->b_u_numhead;
Karsten Hopp eaec1b
  }
Karsten Hopp eaec1b
***************
Karsten Hopp eaec1b
*** 1609,1614 ****
Karsten Hopp eaec1b
--- 1736,1744 ----
Karsten Hopp eaec1b
      while (n > 0)
Karsten Hopp eaec1b
  	U_FREE_LINE(uep->ue_array[--n]);
Karsten Hopp eaec1b
      U_FREE_LINE((char_u *)uep->ue_array);
Karsten Hopp eaec1b
+ #ifdef U_DEBUG
Karsten Hopp eaec1b
+     uep->ue_magic = 0;
Karsten Hopp eaec1b
+ #endif
Karsten Hopp eaec1b
      U_FREE_LINE((char_u *)uep);
Karsten Hopp eaec1b
  }
Karsten Hopp eaec1b
  
Karsten Hopp eaec1b
*** ../vim-7.1.129/src/structs.h	Sun Aug 12 15:50:26 2007
Karsten Hopp eaec1b
--- src/structs.h	Sat Sep 29 15:03:38 2007
Karsten Hopp eaec1b
***************
Karsten Hopp eaec1b
*** 278,283 ****
Karsten Hopp eaec1b
--- 278,286 ----
Karsten Hopp eaec1b
      linenr_T	ue_lcount;	/* linecount when u_save called */
Karsten Hopp eaec1b
      char_u	**ue_array;	/* array of lines in undo block */
Karsten Hopp eaec1b
      long	ue_size;	/* number of lines in ue_array */
Karsten Hopp eaec1b
+ #ifdef U_DEBUG
Karsten Hopp eaec1b
+     int		ue_magic;	/* magic number to check allocation */
Karsten Hopp eaec1b
+ #endif
Karsten Hopp eaec1b
  };
Karsten Hopp eaec1b
  
Karsten Hopp eaec1b
  struct u_header
Karsten Hopp eaec1b
***************
Karsten Hopp eaec1b
*** 300,305 ****
Karsten Hopp eaec1b
--- 303,311 ----
Karsten Hopp eaec1b
      visualinfo_T uh_visual;	/* Visual areas before undo/after redo */
Karsten Hopp eaec1b
  #endif
Karsten Hopp eaec1b
      time_t	uh_time;	/* timestamp when the change was made */
Karsten Hopp eaec1b
+ #ifdef U_DEBUG
Karsten Hopp eaec1b
+     int		uh_magic;	/* magic number to check allocation */
Karsten Hopp eaec1b
+ #endif
Karsten Hopp eaec1b
  };
Karsten Hopp eaec1b
  
Karsten Hopp eaec1b
  /* values for uh_flags */
Karsten Hopp eaec1b
*** ../vim-7.1.129/src/version.c	Mon Oct  1 20:33:45 2007
Karsten Hopp eaec1b
--- src/version.c	Mon Oct  1 22:50:23 2007
Karsten Hopp eaec1b
***************
Karsten Hopp eaec1b
*** 668,669 ****
Karsten Hopp eaec1b
--- 668,671 ----
Karsten Hopp eaec1b
  {   /* Add new patch number below this line */
Karsten Hopp eaec1b
+ /**/
Karsten Hopp eaec1b
+     130,
Karsten Hopp eaec1b
  /**/
Karsten Hopp eaec1b
Karsten Hopp eaec1b
-- 
Karsten Hopp eaec1b
FIRST SOLDIER:  So they wouldn't be able to bring a coconut back anyway.
Karsten Hopp eaec1b
SECOND SOLDIER: Wait a minute! Suppose two swallows carried it together?
Karsten Hopp eaec1b
FIRST SOLDIER:  No, they'd have to have it on a line.
Karsten Hopp eaec1b
                 "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD
Karsten Hopp eaec1b
Karsten Hopp eaec1b
 /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net   \\\
Karsten Hopp eaec1b
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
Karsten Hopp eaec1b
\\\        download, build and distribute -- http://www.A-A-P.org        ///
Karsten Hopp eaec1b
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///