aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2023-08-22 22:48:55 +0800
committerGitHub <noreply@github.com>2023-08-22 22:48:55 +0800
commitb84a67f50ed6141f72d433094a1a611ae4f67924 (patch)
tree489d51091837a31218e6634910a81ff65e225b2d
parente34eb4ccf9c3a9c04127cb8e00742ed2e3316484 (diff)
downloadrneovim-b84a67f50ed6141f72d433094a1a611ae4f67924.tar.gz
rneovim-b84a67f50ed6141f72d433094a1a611ae4f67924.tar.bz2
rneovim-b84a67f50ed6141f72d433094a1a611ae4f67924.zip
vim-patch:9.0.0579: using freed memory when 'tagfunc' wipes out buffer (#24838)
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. https://github.com/vim/vim/commit/0ff01835a40f549c5c4a550502f62a2ac9ac447c Cherry-pick a cmdwin change from patch 9.0.0500. Co-authored-by: Bram Moolenaar <Bram@vim.org>
-rw-r--r--src/nvim/ex_getln.c3
-rw-r--r--src/nvim/insexpand.c24
-rw-r--r--src/nvim/move.c1
-rw-r--r--test/functional/ui/cmdline_spec.lua8
-rw-r--r--test/functional/ui/popupmenu_spec.lua2
-rw-r--r--test/functional/ui/searchhl_spec.lua2
-rw-r--r--test/old/testdir/test_ins_complete.vim20
7 files changed, 48 insertions, 12 deletions
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 6af79bfd21..c401293ccc 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -4572,7 +4572,8 @@ static int open_cmdwin(void)
ccline.cmdlen = (int)strlen(ccline.cmdbuff);
ccline.cmdbufflen = ccline.cmdlen + 1;
ccline.cmdpos = curwin->w_cursor.col;
- if (ccline.cmdpos > ccline.cmdlen) {
+ // If the cursor is on the last character, it probably should be after it.
+ if (ccline.cmdpos == ccline.cmdlen - 1 || ccline.cmdpos > ccline.cmdlen) {
ccline.cmdpos = ccline.cmdlen;
}
if (cmdwin_result == K_IGNORE) {
diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c
index 8285c0c2b8..1a77679abd 100644
--- a/src/nvim/insexpand.c
+++ b/src/nvim/insexpand.c
@@ -64,6 +64,7 @@
#include "nvim/ui.h"
#include "nvim/undo.h"
#include "nvim/vim.h"
+#include "nvim/window.h"
// Definitions used for CTRL-X submode.
// Note: If you change CTRL-X submode, you must also maintain ctrl_x_msgs[]
@@ -161,7 +162,8 @@ struct compl_S {
/// state information used for getting the next set of insert completion
/// matches.
typedef struct {
- char *e_cpt; ///< current entry in 'complete'
+ char *e_cpt_copy; ///< copy of 'complete'
+ char *e_cpt; ///< current entry in "e_cpt_copy"
buf_T *ins_buf; ///< buffer being scanned
pos_T *cur_match_pos; ///< current match position
pos_T prev_match_pos; ///< previous match position
@@ -2219,7 +2221,8 @@ static buf_T *ins_compl_next_buf(buf_T *buf, int flag)
static win_T *wp = NULL;
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;
}
assert(wp);
@@ -3287,6 +3290,7 @@ static bool get_next_completion_match(int type, ins_compl_next_state_T *st, pos_
static int ins_compl_get_exp(pos_T *ini)
{
static ins_compl_next_state_T st;
+ static bool st_cleared = false;
int i;
int found_new_match;
int type = ctrl_x_mode;
@@ -3297,9 +3301,16 @@ static int ins_compl_get_exp(pos_T *ini)
FOR_ALL_BUFFERS(buf) {
buf->b_scanned = false;
}
+ if (!st_cleared) {
+ CLEAR_FIELD(st);
+ st_cleared = true;
+ }
st.found_all = false;
st.ins_buf = curbuf;
- st.e_cpt = (compl_cont_status & CONT_LOCAL) ? "." : curbuf->b_p_cpt;
+ xfree(st.e_cpt_copy);
+ // Make a copy of 'complete', in case the buffer is wiped out.
+ st.e_cpt_copy = xstrdup((compl_cont_status & CONT_LOCAL) ? "." : curbuf->b_p_cpt);
+ st.e_cpt = st.e_cpt_copy == NULL ? "" : st.e_cpt_copy;
st.last_match_pos = st.first_match_pos = *ini;
} else if (st.ins_buf != curbuf && !buf_valid(st.ins_buf)) {
st.ins_buf = curbuf; // In case the buffer was wiped out.
@@ -3599,6 +3610,7 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match
int num_matches = -1;
int todo = count;
const bool started = compl_started;
+ buf_T *const orig_curbuf = curbuf;
// When user complete function return -1 for findstart which is next
// time of 'always', compl_shown_match become NULL.
@@ -3634,6 +3646,12 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match
return -1;
}
+ 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) {
ins_bytes(compl_orig_text + get_compl_len());
diff --git a/src/nvim/move.c b/src/nvim/move.c
index faa491826a..3f4ba3c811 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -622,6 +622,7 @@ int cursor_valid(void)
// w_topline must be valid, you may need to call update_topline() first!
void validate_cursor(void)
{
+ check_cursor();
check_cursor_moved(curwin);
if ((curwin->w_valid & (VALID_WCOL|VALID_WROW)) != (VALID_WCOL|VALID_WROW)) {
curs_columns(curwin, true);
diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua
index 7d87ba4972..4b92ab730d 100644
--- a/test/functional/ui/cmdline_spec.lua
+++ b/test/functional/ui/cmdline_spec.lua
@@ -316,7 +316,7 @@ local function test_cmdline(linegrid)
screen:expect{grid=[[
|
{2:[No Name] }|
- {1::}make^ |
+ {1::}mak^e |
{3:[Command Line] }|
|
]]}
@@ -326,7 +326,7 @@ local function test_cmdline(linegrid)
screen:expect{grid=[[
|
{2:[No Name] }|
- {1::}make^ |
+ {1::}mak^e |
{3:[Command Line] }|
|
]], cmdline={nil, {
@@ -339,7 +339,7 @@ local function test_cmdline(linegrid)
screen:expect{grid=[[
|
{2:[No Name] }|
- {1::}make^ |
+ {1::}mak^e |
{3:[Command Line] }|
|
]], cmdline={nil, {
@@ -352,7 +352,7 @@ local function test_cmdline(linegrid)
screen:expect{grid=[[
|
{2:[No Name] }|
- {1::}make^ |
+ {1::}mak^e |
{3:[Command Line] }|
|
]]}
diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua
index 76038472bd..ea65cf35bd 100644
--- a/test/functional/ui/popupmenu_spec.lua
+++ b/test/functional/ui/popupmenu_spec.lua
@@ -3239,7 +3239,7 @@ describe('builtin popupmenu', function()
|
{3:[No Name] }|
{1::}sign define |
- {1::}sign define^ |
+ {1::}sign defin^e |
{1:~ }|
{1:~ }|
{1:~ }|
diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua
index ec1ebbe4ca..7fd66d6f8a 100644
--- a/test/functional/ui/searchhl_spec.lua
+++ b/test/functional/ui/searchhl_spec.lua
@@ -52,7 +52,7 @@ describe('search highlighting', function()
{1:~ }|
/text^ |
]], win_viewport={
- [2] = {win = {id = 1000}, topline = 0, botline = 3, curline = 0, curcol = 9, linecount = 2, sum_scroll_delta = 0};
+ [2] = {win = {id = 1000}, topline = 0, botline = 3, curline = 0, curcol = 8, linecount = 2, sum_scroll_delta = 0};
}}
end)
diff --git a/test/old/testdir/test_ins_complete.vim b/test/old/testdir/test_ins_complete.vim
index f01a95b6fe..d9b2abffab 100644
--- a/test/old/testdir/test_ins_complete.vim
+++ b/test/old/testdir/test_ins_complete.vim
@@ -645,9 +645,8 @@ func Test_pum_with_preview_win()
call writefile(lines, 'Xpreviewscript')
let buf = RunVimInTerminal('-S Xpreviewscript', #{rows: 12})
- call TermWait(buf, 50)
call term_sendkeys(buf, "Gi\<C-X>\<C-O>")
- call TermWait(buf, 100)
+ call TermWait(buf, 200)
call term_sendkeys(buf, "\<C-N>")
call VerifyScreenDump(buf, 'Test_pum_with_preview_win', {})
@@ -2237,4 +2236,21 @@ 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
+
+
" vim: shiftwidth=2 sts=2 expandtab