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.cmdlen = (int)strlen(ccline.cmdbuff);
|
||||||
ccline.cmdbufflen = ccline.cmdlen + 1;
|
ccline.cmdbufflen = ccline.cmdlen + 1;
|
||||||
ccline.cmdpos = curwin->w_cursor.col;
|
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;
|
ccline.cmdpos = ccline.cmdlen;
|
||||||
}
|
}
|
||||||
if (cmdwin_result == K_IGNORE) {
|
if (cmdwin_result == K_IGNORE) {
|
||||||
|
@ -64,6 +64,7 @@
|
|||||||
#include "nvim/ui.h"
|
#include "nvim/ui.h"
|
||||||
#include "nvim/undo.h"
|
#include "nvim/undo.h"
|
||||||
#include "nvim/vim.h"
|
#include "nvim/vim.h"
|
||||||
|
#include "nvim/window.h"
|
||||||
|
|
||||||
// Definitions used for CTRL-X submode.
|
// Definitions used for CTRL-X submode.
|
||||||
// Note: If you change CTRL-X submode, you must also maintain ctrl_x_msgs[]
|
// 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
|
/// state information used for getting the next set of insert completion
|
||||||
/// matches.
|
/// matches.
|
||||||
typedef struct {
|
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
|
buf_T *ins_buf; ///< buffer being scanned
|
||||||
pos_T *cur_match_pos; ///< current match position
|
pos_T *cur_match_pos; ///< current match position
|
||||||
pos_T prev_match_pos; ///< previous 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;
|
static win_T *wp = NULL;
|
||||||
|
|
||||||
if (flag == 'w') { // just windows
|
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;
|
wp = curwin;
|
||||||
}
|
}
|
||||||
assert(wp);
|
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 int ins_compl_get_exp(pos_T *ini)
|
||||||
{
|
{
|
||||||
static ins_compl_next_state_T st;
|
static ins_compl_next_state_T st;
|
||||||
|
static bool st_cleared = false;
|
||||||
int i;
|
int i;
|
||||||
int found_new_match;
|
int found_new_match;
|
||||||
int type = ctrl_x_mode;
|
int type = ctrl_x_mode;
|
||||||
@ -3297,9 +3301,16 @@ static int ins_compl_get_exp(pos_T *ini)
|
|||||||
FOR_ALL_BUFFERS(buf) {
|
FOR_ALL_BUFFERS(buf) {
|
||||||
buf->b_scanned = false;
|
buf->b_scanned = false;
|
||||||
}
|
}
|
||||||
|
if (!st_cleared) {
|
||||||
|
CLEAR_FIELD(st);
|
||||||
|
st_cleared = true;
|
||||||
|
}
|
||||||
st.found_all = false;
|
st.found_all = false;
|
||||||
st.ins_buf = curbuf;
|
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;
|
st.last_match_pos = st.first_match_pos = *ini;
|
||||||
} else if (st.ins_buf != curbuf && !buf_valid(st.ins_buf)) {
|
} else if (st.ins_buf != curbuf && !buf_valid(st.ins_buf)) {
|
||||||
st.ins_buf = curbuf; // In case the buffer was wiped out.
|
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 num_matches = -1;
|
||||||
int todo = count;
|
int todo = count;
|
||||||
const bool started = compl_started;
|
const bool started = compl_started;
|
||||||
|
buf_T *const orig_curbuf = curbuf;
|
||||||
|
|
||||||
// When user complete function return -1 for findstart which is next
|
// When user complete function return -1 for findstart which is next
|
||||||
// time of 'always', compl_shown_match become NULL.
|
// 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;
|
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.
|
// Insert the text of the new completion, or the compl_leader.
|
||||||
if (compl_no_insert && !started) {
|
if (compl_no_insert && !started) {
|
||||||
ins_bytes(compl_orig_text + get_compl_len());
|
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!
|
// w_topline must be valid, you may need to call update_topline() first!
|
||||||
void validate_cursor(void)
|
void validate_cursor(void)
|
||||||
{
|
{
|
||||||
|
check_cursor();
|
||||||
check_cursor_moved(curwin);
|
check_cursor_moved(curwin);
|
||||||
if ((curwin->w_valid & (VALID_WCOL|VALID_WROW)) != (VALID_WCOL|VALID_WROW)) {
|
if ((curwin->w_valid & (VALID_WCOL|VALID_WROW)) != (VALID_WCOL|VALID_WROW)) {
|
||||||
curs_columns(curwin, true);
|
curs_columns(curwin, true);
|
||||||
|
@ -316,7 +316,7 @@ local function test_cmdline(linegrid)
|
|||||||
screen:expect{grid=[[
|
screen:expect{grid=[[
|
||||||
|
|
|
|
||||||
{2:[No Name] }|
|
{2:[No Name] }|
|
||||||
{1::}make^ |
|
{1::}mak^e |
|
||||||
{3:[Command Line] }|
|
{3:[Command Line] }|
|
||||||
|
|
|
|
||||||
]]}
|
]]}
|
||||||
@ -326,7 +326,7 @@ local function test_cmdline(linegrid)
|
|||||||
screen:expect{grid=[[
|
screen:expect{grid=[[
|
||||||
|
|
|
|
||||||
{2:[No Name] }|
|
{2:[No Name] }|
|
||||||
{1::}make^ |
|
{1::}mak^e |
|
||||||
{3:[Command Line] }|
|
{3:[Command Line] }|
|
||||||
|
|
|
|
||||||
]], cmdline={nil, {
|
]], cmdline={nil, {
|
||||||
@ -339,7 +339,7 @@ local function test_cmdline(linegrid)
|
|||||||
screen:expect{grid=[[
|
screen:expect{grid=[[
|
||||||
|
|
|
|
||||||
{2:[No Name] }|
|
{2:[No Name] }|
|
||||||
{1::}make^ |
|
{1::}mak^e |
|
||||||
{3:[Command Line] }|
|
{3:[Command Line] }|
|
||||||
|
|
|
|
||||||
]], cmdline={nil, {
|
]], cmdline={nil, {
|
||||||
@ -352,7 +352,7 @@ local function test_cmdline(linegrid)
|
|||||||
screen:expect{grid=[[
|
screen:expect{grid=[[
|
||||||
|
|
|
|
||||||
{2:[No Name] }|
|
{2:[No Name] }|
|
||||||
{1::}make^ |
|
{1::}mak^e |
|
||||||
{3:[Command Line] }|
|
{3:[Command Line] }|
|
||||||
|
|
|
|
||||||
]]}
|
]]}
|
||||||
|
@ -3239,7 +3239,7 @@ describe('builtin popupmenu', function()
|
|||||||
|
|
|
|
||||||
{3:[No Name] }|
|
{3:[No Name] }|
|
||||||
{1::}sign define |
|
{1::}sign define |
|
||||||
{1::}sign define^ |
|
{1::}sign defin^e |
|
||||||
{1:~ }|
|
{1:~ }|
|
||||||
{1:~ }|
|
{1:~ }|
|
||||||
{1:~ }|
|
{1:~ }|
|
||||||
|
@ -52,7 +52,7 @@ describe('search highlighting', function()
|
|||||||
{1:~ }|
|
{1:~ }|
|
||||||
/text^ |
|
/text^ |
|
||||||
]], win_viewport={
|
]], 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)
|
end)
|
||||||
|
|
||||||
|
@ -645,9 +645,8 @@ func Test_pum_with_preview_win()
|
|||||||
|
|
||||||
call writefile(lines, 'Xpreviewscript')
|
call writefile(lines, 'Xpreviewscript')
|
||||||
let buf = RunVimInTerminal('-S Xpreviewscript', #{rows: 12})
|
let buf = RunVimInTerminal('-S Xpreviewscript', #{rows: 12})
|
||||||
call TermWait(buf, 50)
|
|
||||||
call term_sendkeys(buf, "Gi\<C-X>\<C-O>")
|
call term_sendkeys(buf, "Gi\<C-X>\<C-O>")
|
||||||
call TermWait(buf, 100)
|
call TermWait(buf, 200)
|
||||||
call term_sendkeys(buf, "\<C-N>")
|
call term_sendkeys(buf, "\<C-N>")
|
||||||
call VerifyScreenDump(buf, 'Test_pum_with_preview_win', {})
|
call VerifyScreenDump(buf, 'Test_pum_with_preview_win', {})
|
||||||
|
|
||||||
@ -2237,4 +2236,21 @@ func Test_ins_complete_end_of_line()
|
|||||||
bwipe!
|
bwipe!
|
||||||
endfunc
|
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
|
" vim: shiftwidth=2 sts=2 expandtab
|
||||||
|
Loading…
Reference in New Issue
Block a user