mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
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.
0ff01835a4
Cherry-pick a cmdwin change from patch 9.0.0500.
Co-authored-by: Bram Moolenaar <Bram@vim.org>
This commit is contained in:
parent
e34eb4ccf9
commit
b84a67f50e
@ -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) {
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
|
@ -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] }|
|
||||
|
|
||||
]]}
|
||||
|
@ -3239,7 +3239,7 @@ describe('builtin popupmenu', function()
|
||||
|
|
||||
{3:[No Name] }|
|
||||
{1::}sign define |
|
||||
{1::}sign define^ |
|
||||
{1::}sign defin^e |
|
||||
{1:~ }|
|
||||
{1:~ }|
|
||||
{1:~ }|
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user