changeset 11424:328a9ee98fb2 v8.0.0596

patch 8.0.0596: crash when complete() called after complete_add() commit https://github.com/vim/vim/commit/4475b623960671898dac6a72b13a8d140402afa6 Author: Bram Moolenaar <Bram@vim.org> Date: Mon May 1 20:46:52 2017 +0200 patch 8.0.0596: crash when complete() called after complete_add() Problem: Crash when complete() is called after complete_add() in 'completefunc'. (Lifepillar) Solution: Bail out if compl_pattern is NULL. (closes #1668) Also avoid using freed memory.
author Christian Brabandt <cb@256bit.org>
date Mon, 01 May 2017 21:00:04 +0200
parents e9a041bb30eb
children 98d6836199ef
files src/edit.c src/testdir/test_popup.vim src/version.c
diffstat 3 files changed, 64 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/src/edit.c
+++ b/src/edit.c
@@ -96,6 +96,7 @@ struct compl_S
 static compl_T    *compl_first_match = NULL;
 static compl_T    *compl_curr_match = NULL;
 static compl_T    *compl_shown_match = NULL;
+static compl_T    *compl_old_match = NULL;
 
 /* After using a cursor key <Enter> selects a match in the popup menu,
  * otherwise it inserts a line break. */
@@ -3431,6 +3432,7 @@ ins_compl_free(void)
     } while (compl_curr_match != NULL && compl_curr_match != compl_first_match);
     compl_first_match = compl_curr_match = NULL;
     compl_shown_match = NULL;
+    compl_old_match = NULL;
 }
 
     static void
@@ -4272,7 +4274,6 @@ ins_compl_get_exp(pos_T *ini)
     char_u	*ptr;
     char_u	*dict = NULL;
     int		dict_f = 0;
-    compl_T	*old_match;
     int		set_match_pos;
 
     if (!compl_started)
@@ -4286,7 +4287,7 @@ ins_compl_get_exp(pos_T *ini)
 	last_match_pos = first_match_pos = *ini;
     }
 
-    old_match = compl_curr_match;	/* remember the last current match */
+    compl_old_match = compl_curr_match;	/* remember the last current match */
     pos = (compl_direction == FORWARD) ? &last_match_pos : &first_match_pos;
     /* For ^N/^P loop over all the flags/windows/buffers in 'complete' */
     for (;;)
@@ -4388,6 +4389,11 @@ ins_compl_get_exp(pos_T *ini)
 	    }
 	}
 
+	/* If complete() was called then compl_pattern has been reset.  The
+	 * following won't work then, bail out. */
+	if (compl_pattern == NULL)
+	    break;
+
 	switch (type)
 	{
 	case -1:
@@ -4621,7 +4627,7 @@ ins_compl_get_exp(pos_T *ini)
 
 	/* check if compl_curr_match has changed, (e.g. other type of
 	 * expansion added something) */
-	if (type != 0 && compl_curr_match != old_match)
+	if (type != 0 && compl_curr_match != compl_old_match)
 	    found_new_match = OK;
 
 	/* break the loop for specialized modes (use 'complete' just for the
@@ -4660,13 +4666,16 @@ ins_compl_get_exp(pos_T *ini)
 	    || (ctrl_x_mode != 0 && !CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode)))
 	i = ins_compl_make_cyclic();
 
-    /* If several matches were added (FORWARD) or the search failed and has
-     * just been made cyclic then we have to move compl_curr_match to the next
-     * or previous entry (if any) -- Acevedo */
-    compl_curr_match = compl_direction == FORWARD ? old_match->cp_next
-							 : old_match->cp_prev;
-    if (compl_curr_match == NULL)
-	compl_curr_match = old_match;
+    if (compl_old_match != NULL)
+    {
+	/* If several matches were added (FORWARD) or the search failed and has
+	 * just been made cyclic then we have to move compl_curr_match to the
+	 * next or previous entry (if any) -- Acevedo */
+	compl_curr_match = compl_direction == FORWARD ? compl_old_match->cp_next
+						    : compl_old_match->cp_prev;
+	if (compl_curr_match == NULL)
+	    compl_curr_match = compl_old_match;
+    }
     return i;
 }
 
--- a/src/testdir/test_popup.vim
+++ b/src/testdir/test_popup.vim
@@ -570,4 +570,47 @@ func Test_completion_comment_formatting(
   bwipe!
 endfunc
 
+fun MessCompleteMonths()
+  for m in split("Jan Feb Mar Apr May Jun Jul Aug Sep")
+    call complete_add(m)
+    if complete_check()
+      break
+    endif
+  endfor
+  return []
+endfun
+
+fun MessCompleteMore()
+  call complete(1, split("Oct Nov Dec"))
+  return []
+endfun
+
+fun MessComplete(findstart, base)
+  if a:findstart
+    let line = getline('.')
+    let start = col('.') - 1
+    while start > 0 && line[start - 1] =~ '\a'
+      let start -= 1
+    endwhile
+    return start
+  else
+    call MessCompleteMonths()
+    call MessCompleteMore()
+    return []
+  endif
+endf
+
+func Test_complete_func_mess()
+  " Calling complete() after complete_add() in 'completefunc' is wrong, but it
+  " should not crash.
+  set completefunc=MessComplete
+  new
+  call setline(1, 'Ju')
+  call feedkeys("A\<c-x>\<c-u>/\<esc>", 'tx')
+  call assert_equal('Oct/Oct', getline(1))
+  bwipe!
+  set completefunc=
+endfunc
+
+
 " vim: shiftwidth=2 sts=2 expandtab
--- a/src/version.c
+++ b/src/version.c
@@ -765,6 +765,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    596,
+/**/
     595,
 /**/
     594,