diff options
author | zeertzjq <zeertzjq@outlook.com> | 2023-08-22 22:48:55 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-08-22 22:48:55 +0800 |
commit | b84a67f50ed6141f72d433094a1a611ae4f67924 (patch) | |
tree | 489d51091837a31218e6634910a81ff65e225b2d | |
parent | e34eb4ccf9c3a9c04127cb8e00742ed2e3316484 (diff) | |
download | rneovim-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.c | 3 | ||||
-rw-r--r-- | src/nvim/insexpand.c | 24 | ||||
-rw-r--r-- | src/nvim/move.c | 1 | ||||
-rw-r--r-- | test/functional/ui/cmdline_spec.lua | 8 | ||||
-rw-r--r-- | test/functional/ui/popupmenu_spec.lua | 2 | ||||
-rw-r--r-- | test/functional/ui/searchhl_spec.lua | 2 | ||||
-rw-r--r-- | test/old/testdir/test_ins_complete.vim | 20 |
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 |