5c71fd5
To: vim-dev@vim.org
5c71fd5
Subject: Patch 7.2.080
5c71fd5
Fcc: outbox
5c71fd5
From: Bram Moolenaar <Bram@moolenaar.net>
5c71fd5
Mime-Version: 1.0
5c71fd5
Content-Type: text/plain; charset=ISO-8859-1
5c71fd5
Content-Transfer-Encoding: 8bit
5c71fd5
------------
5c71fd5
5c71fd5
Patch 7.2.080
5c71fd5
Problem:    When typing a composing character just after starting completion
5c71fd5
	    may access memory before its allocation point. (Dominique Pelle)
5c71fd5
Solution:   Don't delete before the completion start column.  Add extra checks
5c71fd5
	    for the offset not being negative.
5c71fd5
Files:	    src/edit.c
5c71fd5
5c71fd5
5c71fd5
*** ../vim-7.2.079/src/edit.c	Wed Aug  6 18:56:55 2008
5c71fd5
--- src/edit.c	Tue Jan 13 12:05:57 2009
5c71fd5
***************
5c71fd5
*** 147,152 ****
5c71fd5
--- 147,153 ----
5c71fd5
  static int  ins_compl_bs __ARGS((void));
5c71fd5
  static void ins_compl_new_leader __ARGS((void));
5c71fd5
  static void ins_compl_addleader __ARGS((int c));
5c71fd5
+ static int ins_compl_len __ARGS((void));
5c71fd5
  static void ins_compl_restart __ARGS((void));
5c71fd5
  static void ins_compl_set_original_text __ARGS((char_u *str));
5c71fd5
  static void ins_compl_addfrommatch __ARGS((void));
5c71fd5
***************
5c71fd5
*** 197,203 ****
5c71fd5
  static void mb_replace_pop_ins __ARGS((int cc));
5c71fd5
  #endif
5c71fd5
  static void replace_flush __ARGS((void));
5c71fd5
! static void replace_do_bs __ARGS((void));
5c71fd5
  #ifdef FEAT_CINDENT
5c71fd5
  static int cindent_on __ARGS((void));
5c71fd5
  #endif
5c71fd5
--- 198,205 ----
5c71fd5
  static void mb_replace_pop_ins __ARGS((int cc));
5c71fd5
  #endif
5c71fd5
  static void replace_flush __ARGS((void));
5c71fd5
! static void replace_do_bs __ARGS((int limit_col));
5c71fd5
! static int del_char_after_col __ARGS((int limit_col));
5c71fd5
  #ifdef FEAT_CINDENT
5c71fd5
  static int cindent_on __ARGS((void));
5c71fd5
  #endif
5c71fd5
***************
5c71fd5
*** 1933,1938 ****
5c71fd5
--- 1935,1942 ----
5c71fd5
  /*
5c71fd5
   * Backspace the cursor until the given column.  Handles REPLACE and VREPLACE
5c71fd5
   * modes correctly.  May also be used when not in insert mode at all.
5c71fd5
+  * Will attempt not to go before "col" even when there is a composing
5c71fd5
+  * character.
5c71fd5
   */
5c71fd5
      void
5c71fd5
  backspace_until_column(col)
5c71fd5
***************
5c71fd5
*** 1942,1954 ****
5c71fd5
      {
5c71fd5
  	curwin->w_cursor.col--;
5c71fd5
  	if (State & REPLACE_FLAG)
5c71fd5
! 	    replace_do_bs();
5c71fd5
! 	else
5c71fd5
! 	    (void)del_char(FALSE);
5c71fd5
      }
5c71fd5
  }
5c71fd5
  #endif
5c71fd5
  
5c71fd5
  #if defined(FEAT_INS_EXPAND) || defined(PROTO)
5c71fd5
  /*
5c71fd5
   * CTRL-X pressed in Insert mode.
5c71fd5
--- 1946,1994 ----
5c71fd5
      {
5c71fd5
  	curwin->w_cursor.col--;
5c71fd5
  	if (State & REPLACE_FLAG)
5c71fd5
! 	    replace_do_bs(col);
5c71fd5
! 	else if (!del_char_after_col(col))
5c71fd5
! 	    break;
5c71fd5
      }
5c71fd5
  }
5c71fd5
  #endif
5c71fd5
  
5c71fd5
+ /*
5c71fd5
+  * Like del_char(), but make sure not to go before column "limit_col".
5c71fd5
+  * Only matters when there are composing characters.
5c71fd5
+  * Return TRUE when something was deleted.
5c71fd5
+  */
5c71fd5
+    static int
5c71fd5
+ del_char_after_col(limit_col)
5c71fd5
+     int limit_col;
5c71fd5
+ {
5c71fd5
+ #ifdef FEAT_MBYTE
5c71fd5
+     if (enc_utf8 && limit_col >= 0)
5c71fd5
+     {
5c71fd5
+ 	int ecol = curwin->w_cursor.col + 1;
5c71fd5
+ 
5c71fd5
+ 	/* Make sure the cursor is at the start of a character, but
5c71fd5
+ 	 * skip forward again when going too far back because of a
5c71fd5
+ 	 * composing character. */
5c71fd5
+ 	mb_adjust_cursor();
5c71fd5
+ 	while (curwin->w_cursor.col < limit_col)
5c71fd5
+ 	{
5c71fd5
+ 	    int l = utf_ptr2len(ml_get_cursor());
5c71fd5
+ 
5c71fd5
+ 	    if (l == 0)  /* end of line */
5c71fd5
+ 		break;
5c71fd5
+ 	    curwin->w_cursor.col += l;
5c71fd5
+ 	}
5c71fd5
+ 	if (*ml_get_cursor() == NUL || curwin->w_cursor.col == ecol)
5c71fd5
+ 	    return FALSE;
5c71fd5
+ 	del_bytes((long)(ecol - curwin->w_cursor.col), FALSE, TRUE);
5c71fd5
+     }
5c71fd5
+     else
5c71fd5
+ #endif
5c71fd5
+ 	(void)del_char(FALSE);
5c71fd5
+     return TRUE;
5c71fd5
+ }
5c71fd5
+ 
5c71fd5
  #if defined(FEAT_INS_EXPAND) || defined(PROTO)
5c71fd5
  /*
5c71fd5
   * CTRL-X pressed in Insert mode.
5c71fd5
***************
5c71fd5
*** 2418,2424 ****
5c71fd5
  	{
5c71fd5
  	    had_match = (curwin->w_cursor.col > compl_col);
5c71fd5
  	    ins_compl_delete();
5c71fd5
! 	    ins_bytes(compl_leader + curwin->w_cursor.col - compl_col);
5c71fd5
  	    ins_redraw(FALSE);
5c71fd5
  
5c71fd5
  	    /* When the match isn't there (to avoid matching itself) remove it
5c71fd5
--- 2458,2464 ----
5c71fd5
  	{
5c71fd5
  	    had_match = (curwin->w_cursor.col > compl_col);
5c71fd5
  	    ins_compl_delete();
5c71fd5
! 	    ins_bytes(compl_leader + ins_compl_len());
5c71fd5
  	    ins_redraw(FALSE);
5c71fd5
  
5c71fd5
  	    /* When the match isn't there (to avoid matching itself) remove it
5c71fd5
***************
5c71fd5
*** 2470,2476 ****
5c71fd5
  	    *p = NUL;
5c71fd5
  	    had_match = (curwin->w_cursor.col > compl_col);
5c71fd5
  	    ins_compl_delete();
5c71fd5
! 	    ins_bytes(compl_leader + curwin->w_cursor.col - compl_col);
5c71fd5
  	    ins_redraw(FALSE);
5c71fd5
  
5c71fd5
  	    /* When the match isn't there (to avoid matching itself) remove it
5c71fd5
--- 2510,2516 ----
5c71fd5
  	    *p = NUL;
5c71fd5
  	    had_match = (curwin->w_cursor.col > compl_col);
5c71fd5
  	    ins_compl_delete();
5c71fd5
! 	    ins_bytes(compl_leader + ins_compl_len());
5c71fd5
  	    ins_redraw(FALSE);
5c71fd5
  
5c71fd5
  	    /* When the match isn't there (to avoid matching itself) remove it
5c71fd5
***************
5c71fd5
*** 3209,3215 ****
5c71fd5
  {
5c71fd5
      ins_compl_del_pum();
5c71fd5
      ins_compl_delete();
5c71fd5
!     ins_bytes(compl_leader + curwin->w_cursor.col - compl_col);
5c71fd5
      compl_used_match = FALSE;
5c71fd5
  
5c71fd5
      if (compl_started)
5c71fd5
--- 3249,3255 ----
5c71fd5
  {
5c71fd5
      ins_compl_del_pum();
5c71fd5
      ins_compl_delete();
5c71fd5
!     ins_bytes(compl_leader + ins_compl_len());
5c71fd5
      compl_used_match = FALSE;
5c71fd5
  
5c71fd5
      if (compl_started)
5c71fd5
***************
5c71fd5
*** 3264,3269 ****
5c71fd5
--- 3304,3323 ----
5c71fd5
  }
5c71fd5
  
5c71fd5
  /*
5c71fd5
+  * Return the length of the completion, from the completion start column to
5c71fd5
+  * the cursor column.  Making sure it never goes below zero.
5c71fd5
+  */
5c71fd5
+     static int
5c71fd5
+ ins_compl_len()
5c71fd5
+ {
5c71fd5
+     int off = curwin->w_cursor.col - compl_col;
5c71fd5
+ 
5c71fd5
+     if (off < 0)
5c71fd5
+ 	return 0;
5c71fd5
+     return off;
5c71fd5
+ }
5c71fd5
+ 
5c71fd5
+ /*
5c71fd5
   * Append one character to the match leader.  May reduce the number of
5c71fd5
   * matches.
5c71fd5
   */
5c71fd5
***************
5c71fd5
*** 3621,3630 ****
5c71fd5
  	    {
5c71fd5
  		ins_compl_delete();
5c71fd5
  		if (compl_leader != NULL)
5c71fd5
! 		    ins_bytes(compl_leader + curwin->w_cursor.col - compl_col);
5c71fd5
  		else if (compl_first_match != NULL)
5c71fd5
! 		    ins_bytes(compl_orig_text
5c71fd5
! 					  + curwin->w_cursor.col - compl_col);
5c71fd5
  		retval = TRUE;
5c71fd5
  	    }
5c71fd5
  
5c71fd5
--- 3675,3683 ----
5c71fd5
  	    {
5c71fd5
  		ins_compl_delete();
5c71fd5
  		if (compl_leader != NULL)
5c71fd5
! 		    ins_bytes(compl_leader + ins_compl_len());
5c71fd5
  		else if (compl_first_match != NULL)
5c71fd5
! 		    ins_bytes(compl_orig_text + ins_compl_len());
5c71fd5
  		retval = TRUE;
5c71fd5
  	    }
5c71fd5
  
5c71fd5
***************
5c71fd5
*** 4256,4262 ****
5c71fd5
      static void
5c71fd5
  ins_compl_insert()
5c71fd5
  {
5c71fd5
!     ins_bytes(compl_shown_match->cp_str + curwin->w_cursor.col - compl_col);
5c71fd5
      if (compl_shown_match->cp_flags & ORIGINAL_TEXT)
5c71fd5
  	compl_used_match = FALSE;
5c71fd5
      else
5c71fd5
--- 4309,4315 ----
5c71fd5
      static void
5c71fd5
  ins_compl_insert()
5c71fd5
  {
5c71fd5
!     ins_bytes(compl_shown_match->cp_str + ins_compl_len());
5c71fd5
      if (compl_shown_match->cp_flags & ORIGINAL_TEXT)
5c71fd5
  	compl_used_match = FALSE;
5c71fd5
      else
5c71fd5
***************
5c71fd5
*** 4425,4431 ****
5c71fd5
  	if (!compl_get_longest || compl_used_match)
5c71fd5
  	    ins_compl_insert();
5c71fd5
  	else
5c71fd5
! 	    ins_bytes(compl_leader + curwin->w_cursor.col - compl_col);
5c71fd5
      }
5c71fd5
      else
5c71fd5
  	compl_used_match = FALSE;
5c71fd5
--- 4478,4484 ----
5c71fd5
  	if (!compl_get_longest || compl_used_match)
5c71fd5
  	    ins_compl_insert();
5c71fd5
  	else
5c71fd5
! 	    ins_bytes(compl_leader + ins_compl_len());
5c71fd5
      }
5c71fd5
      else
5c71fd5
  	compl_used_match = FALSE;
5c71fd5
***************
5c71fd5
*** 7123,7131 ****
5c71fd5
   * cc == 0: character was inserted, delete it
5c71fd5
   * cc > 0: character was replaced, put cc (first byte of original char) back
5c71fd5
   * and check for more characters to be put back
5c71fd5
   */
5c71fd5
      static void
5c71fd5
! replace_do_bs()
5c71fd5
  {
5c71fd5
      int		cc;
5c71fd5
  #ifdef FEAT_VREPLACE
5c71fd5
--- 7176,7187 ----
5c71fd5
   * cc == 0: character was inserted, delete it
5c71fd5
   * cc > 0: character was replaced, put cc (first byte of original char) back
5c71fd5
   * and check for more characters to be put back
5c71fd5
+  * When "limit_col" is >= 0, don't delete before this column.  Matters when
5c71fd5
+  * using composing characters, use del_char_after_col() instead of del_char().
5c71fd5
   */
5c71fd5
      static void
5c71fd5
! replace_do_bs(limit_col)
5c71fd5
!     int		limit_col;
5c71fd5
  {
5c71fd5
      int		cc;
5c71fd5
  #ifdef FEAT_VREPLACE
5c71fd5
***************
5c71fd5
*** 7153,7159 ****
5c71fd5
  #ifdef FEAT_MBYTE
5c71fd5
  	if (has_mbyte)
5c71fd5
  	{
5c71fd5
! 	    del_char(FALSE);
5c71fd5
  # ifdef FEAT_VREPLACE
5c71fd5
  	    if (State & VREPLACE_FLAG)
5c71fd5
  		orig_len = (int)STRLEN(ml_get_cursor());
5c71fd5
--- 7209,7215 ----
5c71fd5
  #ifdef FEAT_MBYTE
5c71fd5
  	if (has_mbyte)
5c71fd5
  	{
5c71fd5
! 	    (void)del_char_after_col(limit_col);
5c71fd5
  # ifdef FEAT_VREPLACE
5c71fd5
  	    if (State & VREPLACE_FLAG)
5c71fd5
  		orig_len = (int)STRLEN(ml_get_cursor());
5c71fd5
***************
5c71fd5
*** 7203,7209 ****
5c71fd5
  	changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col);
5c71fd5
      }
5c71fd5
      else if (cc == 0)
5c71fd5
! 	(void)del_char(FALSE);
5c71fd5
  }
5c71fd5
  
5c71fd5
  #ifdef FEAT_CINDENT
5c71fd5
--- 7259,7265 ----
5c71fd5
  	changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col);
5c71fd5
      }
5c71fd5
      else if (cc == 0)
5c71fd5
! 	(void)del_char_after_col(limit_col);
5c71fd5
  }
5c71fd5
  
5c71fd5
  #ifdef FEAT_CINDENT
5c71fd5
***************
5c71fd5
*** 8239,8245 ****
5c71fd5
  	 * Replace mode */
5c71fd5
  	if (curwin->w_cursor.lnum != Insstart.lnum
5c71fd5
  		|| curwin->w_cursor.col >= Insstart.col)
5c71fd5
! 	    replace_do_bs();
5c71fd5
      }
5c71fd5
      else
5c71fd5
  	(void)del_char(FALSE);
5c71fd5
--- 8295,8301 ----
5c71fd5
  	 * Replace mode */
5c71fd5
  	if (curwin->w_cursor.lnum != Insstart.lnum
5c71fd5
  		|| curwin->w_cursor.col >= Insstart.col)
5c71fd5
! 	    replace_do_bs(-1);
5c71fd5
      }
5c71fd5
      else
5c71fd5
  	(void)del_char(FALSE);
5c71fd5
***************
5c71fd5
*** 8556,8562 ****
5c71fd5
  		break;
5c71fd5
  	    }
5c71fd5
  	    if (State & REPLACE_FLAG)
5c71fd5
! 		replace_do_bs();
5c71fd5
  	    else
5c71fd5
  	    {
5c71fd5
  #ifdef FEAT_MBYTE
5c71fd5
--- 8612,8618 ----
5c71fd5
  		break;
5c71fd5
  	    }
5c71fd5
  	    if (State & REPLACE_FLAG)
5c71fd5
! 		replace_do_bs(-1);
5c71fd5
  	    else
5c71fd5
  	    {
5c71fd5
  #ifdef FEAT_MBYTE
5c71fd5
*** ../vim-7.2.079/src/version.c	Tue Jan  6 16:13:42 2009
5c71fd5
--- src/version.c	Tue Jan 13 12:25:29 2009
5c71fd5
***************
5c71fd5
*** 678,679 ****
5c71fd5
--- 678,681 ----
5c71fd5
  {   /* Add new patch number below this line */
5c71fd5
+ /**/
5c71fd5
+     80,
5c71fd5
  /**/
5c71fd5
5c71fd5
-- 
5c71fd5
At some point in the project somebody will start whining about the need to
5c71fd5
determine the project "requirements".  This involves interviewing people who
5c71fd5
don't know what they want but, curiously, know exactly when they need it.
5c71fd5
				(Scott Adams - The Dilbert principle)
5c71fd5
5c71fd5
 /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net   \\\
5c71fd5
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
5c71fd5
\\\        download, build and distribute -- http://www.A-A-P.org        ///
5c71fd5
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///