138 lines
4.2 KiB
Diff
138 lines
4.2 KiB
Diff
From 0ff01835a40f549c5c4a550502f62a2ac9ac447c Mon Sep 17 00:00:00 2001
|
||
From: Bram Moolenaar <Bram@vim.org>
|
||
Date: Sat, 24 Sep 2022 19:20:30 +0100
|
||
Subject: [PATCH] patch 9.0.0579: using freed memory when 'tagfunc' wipes out
|
||
buffer
|
||
|
||
Problem: Using freed memory when 'tagfunc' wipes out buffer that holds
|
||
'complete'.
|
||
Solution: Make a copy of the option. Make sure cursor position is valid.
|
||
---
|
||
src/insexpand.c | 39 +++++++++++++++++++++++++++----
|
||
src/move.c | 1 +
|
||
src/testdir/test_ins_complete.vim | 16 +++++++++++++
|
||
3 files changed, 51 insertions(+), 5 deletions(-)
|
||
|
||
diff --git a/src/insexpand.c b/src/insexpand.c
|
||
index a23d2d6..647297d 100644
|
||
--- a/src/insexpand.c
|
||
+++ b/src/insexpand.c
|
||
@@ -2210,7 +2210,8 @@ ins_compl_next_buf(buf_T *buf, int flag)
|
||
|
||
if (flag == 'w') // just windows
|
||
{
|
||
- if (buf == curbuf || wp == NULL) // first call for this flag/expansion
|
||
+ if (buf == curbuf || !win_valid(wp))
|
||
+ // first call for this flag/expansion or window was closed
|
||
wp = curwin;
|
||
while ((wp = (wp->w_next != NULL ? wp->w_next : firstwin)) != curwin
|
||
&& wp->w_buffer->b_scanned)
|
||
@@ -2672,6 +2673,7 @@ ins_compl_get_exp(pos_T *ini)
|
||
static pos_T first_match_pos;
|
||
static pos_T last_match_pos;
|
||
static char_u *e_cpt = (char_u *)""; // curr. entry in 'complete'
|
||
+ static char_u *e_cpt_copy = (char_u *)""; // copy of 'complete'
|
||
static int found_all = FALSE; // Found all matches of a
|
||
// certain type.
|
||
static buf_T *ins_buf = NULL; // buffer being scanned
|
||
@@ -2690,15 +2692,34 @@ ins_compl_get_exp(pos_T *ini)
|
||
char_u *dict = NULL;
|
||
int dict_f = 0;
|
||
int set_match_pos;
|
||
+ static int st_cleared = FALSE;
|
||
|
||
if (!compl_started)
|
||
{
|
||
- FOR_ALL_BUFFERS(ins_buf)
|
||
- ins_buf->b_scanned = 0;
|
||
+ buf_T *buf;
|
||
+
|
||
+ FOR_ALL_BUFFERS(buf)
|
||
+ buf->b_scanned = 0;
|
||
+ if (!st_cleared)
|
||
+ {
|
||
+ e_cpt = NULL;
|
||
+ e_cpt_copy = NULL;
|
||
+ ins_buf = NULL;
|
||
+ set_match_pos = 0;
|
||
+ vim_memset(&first_match_pos, 0, sizeof(first_match_pos));
|
||
+ vim_memset(&last_match_pos, 0, sizeof(last_match_pos));
|
||
+ found_all = FALSE;
|
||
+ dict = NULL;
|
||
+ dict_f = 0;
|
||
+ st_cleared = TRUE;
|
||
+ }
|
||
found_all = FALSE;
|
||
ins_buf = curbuf;
|
||
- e_cpt = (compl_cont_status & CONT_LOCAL)
|
||
- ? (char_u *)"." : curbuf->b_p_cpt;
|
||
+ vim_free(e_cpt_copy);
|
||
+ // Make a copy of 'complete', if case the buffer is wiped out.
|
||
+ e_cpt_copy = vim_strsave((compl_cont_status & CONT_LOCAL)
|
||
+ ? (char_u *)"." : curbuf->b_p_cpt);
|
||
+ e_cpt = e_cpt_copy == NULL ? (char_u *)"" : e_cpt_copy;
|
||
last_match_pos = first_match_pos = *ini;
|
||
}
|
||
else if (ins_buf != curbuf && !buf_valid(ins_buf))
|
||
@@ -3204,6 +3225,7 @@ ins_compl_next(
|
||
int found_end = FALSE;
|
||
int advance;
|
||
int started = compl_started;
|
||
+ buf_T *orig_curbuf = curbuf;
|
||
|
||
// When user complete function return -1 for findstart which is next
|
||
// time of 'always', compl_shown_match become NULL.
|
||
@@ -3336,6 +3358,13 @@ ins_compl_next(
|
||
}
|
||
}
|
||
|
||
+ if (curbuf != orig_curbuf)
|
||
+ {
|
||
+ // In case some completion function switched buffer, don't want to
|
||
+ // insert the completion elsewhere.
|
||
+ return -1;
|
||
+ }
|
||
+
|
||
// Insert the text of the new completion, or the compl_leader.
|
||
if (compl_no_insert && !started)
|
||
{
|
||
diff --git a/src/move.c b/src/move.c
|
||
index 10165ef..1d7bcfb 100644
|
||
--- a/src/move.c
|
||
+++ b/src/move.c
|
||
@@ -637,6 +637,7 @@ cursor_valid(void)
|
||
void
|
||
validate_cursor(void)
|
||
{
|
||
+ check_cursor();
|
||
check_cursor_moved(curwin);
|
||
if ((curwin->w_valid & (VALID_WCOL|VALID_WROW)) != (VALID_WCOL|VALID_WROW))
|
||
curs_columns(TRUE);
|
||
diff --git a/src/testdir/test_ins_complete.vim b/src/testdir/test_ins_complete.vim
|
||
index 39ece18..1b53987 100644
|
||
--- a/src/testdir/test_ins_complete.vim
|
||
+++ b/src/testdir/test_ins_complete.vim
|
||
@@ -427,3 +427,19 @@ func Test_ins_complete_end_of_line()
|
||
|
||
bwipe!
|
||
endfunc
|
||
+
|
||
+func s:Tagfunc(t,f,o)
|
||
+ bwipe!
|
||
+ return []
|
||
+endfunc
|
||
+
|
||
+" This was using freed memory, since 'complete' was in a wiped out buffer.
|
||
+" Also using a window that was closed.
|
||
+func Test_tagfunc_wipes_out_buffer()
|
||
+ new
|
||
+ set complete=.,t,w,b,u,i
|
||
+ se tagfunc=s:Tagfunc
|
||
+ sil norm i
|
||
+
|
||
+ bwipe!
|
||
+endfunc
|
||
--
|
||
2.33.0
|
||
|