mirror of
https://github.com/neovim/neovim.git
synced 2025-09-08 04:18:18 +00:00
Merge pull request #7751 from jamessan/vim-8.0.0590
[RFC] vim-patch:8.0.0590,8.0.0595,8.0.0597,8.0.0606
This commit is contained in:
@@ -5173,6 +5173,8 @@ bool garbage_collect(bool testing)
|
|||||||
ABORTING(set_ref_list)(sub.additional_elements, copyID);
|
ABORTING(set_ref_list)(sub.additional_elements, copyID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ABORTING(set_ref_in_quickfix)(copyID);
|
||||||
|
|
||||||
bool did_free = false;
|
bool did_free = false;
|
||||||
if (!abort) {
|
if (!abort) {
|
||||||
// 2. Free lists and dictionaries that are not referenced.
|
// 2. Free lists and dictionaries that are not referenced.
|
||||||
|
@@ -85,6 +85,7 @@ typedef struct qf_list_S {
|
|||||||
int qf_nonevalid; // TRUE if not a single valid entry found
|
int qf_nonevalid; // TRUE if not a single valid entry found
|
||||||
char_u *qf_title; // title derived from the command that created
|
char_u *qf_title; // title derived from the command that created
|
||||||
// the error list
|
// the error list
|
||||||
|
typval_T *qf_ctx; // context set by setqflist/setloclist
|
||||||
} qf_list_T;
|
} qf_list_T;
|
||||||
|
|
||||||
struct qf_info_S {
|
struct qf_info_S {
|
||||||
@@ -800,7 +801,7 @@ restofline:
|
|||||||
fields->type = *regmatch.startp[i];
|
fields->type = *regmatch.startp[i];
|
||||||
}
|
}
|
||||||
if (fmt_ptr->flags == '+' && !qi->qf_multiscan) { // %+
|
if (fmt_ptr->flags == '+' && !qi->qf_multiscan) { // %+
|
||||||
if (linelen > fields->errmsglen) {
|
if (linelen >= fields->errmsglen) {
|
||||||
// linelen + null terminator
|
// linelen + null terminator
|
||||||
fields->errmsg = xrealloc(fields->errmsg, linelen + 1);
|
fields->errmsg = xrealloc(fields->errmsg, linelen + 1);
|
||||||
fields->errmsglen = linelen + 1;
|
fields->errmsglen = linelen + 1;
|
||||||
@@ -811,7 +812,7 @@ restofline:
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
len = (size_t)(regmatch.endp[i] - regmatch.startp[i]);
|
len = (size_t)(regmatch.endp[i] - regmatch.startp[i]);
|
||||||
if (len > fields->errmsglen) {
|
if (len >= fields->errmsglen) {
|
||||||
// len + null terminator
|
// len + null terminator
|
||||||
fields->errmsg = xrealloc(fields->errmsg, len + 1);
|
fields->errmsg = xrealloc(fields->errmsg, len + 1);
|
||||||
fields->errmsglen = len + 1;
|
fields->errmsglen = len + 1;
|
||||||
@@ -888,7 +889,7 @@ restofline:
|
|||||||
fields->namebuf[0] = NUL; // no match found, remove file name
|
fields->namebuf[0] = NUL; // no match found, remove file name
|
||||||
fields->lnum = 0; // don't jump to this line
|
fields->lnum = 0; // don't jump to this line
|
||||||
fields->valid = false;
|
fields->valid = false;
|
||||||
if (linelen > fields->errmsglen) {
|
if (linelen >= fields->errmsglen) {
|
||||||
// linelen + null terminator
|
// linelen + null terminator
|
||||||
fields->errmsg = xrealloc(fields->errmsg, linelen + 1);
|
fields->errmsg = xrealloc(fields->errmsg, linelen + 1);
|
||||||
fields->errmsglen = linelen + 1;
|
fields->errmsglen = linelen + 1;
|
||||||
@@ -1409,6 +1410,13 @@ void copy_loclist(win_T *from, win_T *to)
|
|||||||
else
|
else
|
||||||
to_qfl->qf_title = NULL;
|
to_qfl->qf_title = NULL;
|
||||||
|
|
||||||
|
if (from_qfl->qf_ctx != NULL) {
|
||||||
|
to_qfl->qf_ctx = xcalloc(1, sizeof(typval_T));
|
||||||
|
tv_copy(from_qfl->qf_ctx, to_qfl->qf_ctx);
|
||||||
|
} else {
|
||||||
|
to_qfl->qf_ctx = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (from_qfl->qf_count) {
|
if (from_qfl->qf_count) {
|
||||||
qfline_T *from_qfp;
|
qfline_T *from_qfp;
|
||||||
qfline_T *prevp;
|
qfline_T *prevp;
|
||||||
@@ -2410,6 +2418,8 @@ static void qf_free(qf_info_T *qi, int idx)
|
|||||||
qi->qf_lists[idx].qf_start = NULL;
|
qi->qf_lists[idx].qf_start = NULL;
|
||||||
qi->qf_lists[idx].qf_ptr = NULL;
|
qi->qf_lists[idx].qf_ptr = NULL;
|
||||||
qi->qf_lists[idx].qf_title = NULL;
|
qi->qf_lists[idx].qf_title = NULL;
|
||||||
|
tv_free(qi->qf_lists[idx].qf_ctx);
|
||||||
|
qi->qf_lists[idx].qf_ctx = NULL;
|
||||||
qi->qf_lists[idx].qf_index = 0;
|
qi->qf_lists[idx].qf_index = 0;
|
||||||
qi->qf_lists[idx].qf_start = NULL;
|
qi->qf_lists[idx].qf_start = NULL;
|
||||||
qi->qf_lists[idx].qf_last = NULL;
|
qi->qf_lists[idx].qf_last = NULL;
|
||||||
@@ -4060,6 +4070,7 @@ enum {
|
|||||||
QF_GETLIST_ITEMS = 0x2,
|
QF_GETLIST_ITEMS = 0x2,
|
||||||
QF_GETLIST_NR = 0x4,
|
QF_GETLIST_NR = 0x4,
|
||||||
QF_GETLIST_WINID = 0x8,
|
QF_GETLIST_WINID = 0x8,
|
||||||
|
QF_GETLIST_CONTEXT = 0x10,
|
||||||
QF_GETLIST_ALL = 0xFF
|
QF_GETLIST_ALL = 0xFF
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -4110,6 +4121,10 @@ int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict)
|
|||||||
flags |= QF_GETLIST_WINID;
|
flags |= QF_GETLIST_WINID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tv_dict_find(what, S_LEN("context")) != NULL) {
|
||||||
|
flags |= QF_GETLIST_CONTEXT;
|
||||||
|
}
|
||||||
|
|
||||||
if (flags & QF_GETLIST_TITLE) {
|
if (flags & QF_GETLIST_TITLE) {
|
||||||
char_u *t = qi->qf_lists[qf_idx].qf_title;
|
char_u *t = qi->qf_lists[qf_idx].qf_title;
|
||||||
if (t == NULL) {
|
if (t == NULL) {
|
||||||
@@ -4127,6 +4142,20 @@ int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((status == OK) && (flags & QF_GETLIST_CONTEXT)) {
|
||||||
|
if (qi->qf_lists[qf_idx].qf_ctx != NULL) {
|
||||||
|
di = tv_dict_item_alloc_len(S_LEN("context"));
|
||||||
|
if (di != NULL) {
|
||||||
|
tv_copy(qi->qf_lists[qf_idx].qf_ctx, &di->di_tv);
|
||||||
|
if (tv_dict_add(retdict, di) == FAIL) {
|
||||||
|
tv_dict_item_free(di);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
status = tv_dict_add_str(retdict, S_LEN("context"), "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4249,7 +4278,10 @@ static int qf_set_properties(qf_info_T *qi, dict_T *what, int action)
|
|||||||
if ((di = tv_dict_find(what, S_LEN("nr"))) != NULL) {
|
if ((di = tv_dict_find(what, S_LEN("nr"))) != NULL) {
|
||||||
// Use the specified quickfix/location list
|
// Use the specified quickfix/location list
|
||||||
if (di->di_tv.v_type == VAR_NUMBER) {
|
if (di->di_tv.v_type == VAR_NUMBER) {
|
||||||
|
// for zero use the current list
|
||||||
|
if (di->di_tv.vval.v_number != 0) {
|
||||||
qf_idx = (int)di->di_tv.vval.v_number - 1;
|
qf_idx = (int)di->di_tv.vval.v_number - 1;
|
||||||
|
}
|
||||||
if (qf_idx < 0 || qf_idx >= qi->qf_listcount) {
|
if (qf_idx < 0 || qf_idx >= qi->qf_listcount) {
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
@@ -4276,6 +4308,14 @@ static int qf_set_properties(qf_info_T *qi, dict_T *what, int action)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((di = tv_dict_find(what, S_LEN("context"))) != NULL) {
|
||||||
|
tv_free(qi->qf_lists[qf_idx].qf_ctx);
|
||||||
|
|
||||||
|
typval_T *ctx = xcalloc(1, sizeof(typval_T));
|
||||||
|
tv_copy(&di->di_tv, ctx);
|
||||||
|
qi->qf_lists[qf_idx].qf_ctx = ctx;
|
||||||
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4362,6 +4402,42 @@ int set_errorlist(win_T *wp, list_T *list, int action, char_u *title,
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool mark_quickfix_ctx(qf_info_T *qi, int copyID)
|
||||||
|
{
|
||||||
|
bool abort = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < LISTCOUNT && !abort; i++) {
|
||||||
|
typval_T *ctx = qi->qf_lists[i].qf_ctx;
|
||||||
|
if (ctx != NULL && ctx->v_type != VAR_NUMBER
|
||||||
|
&& ctx->v_type != VAR_STRING && ctx->v_type != VAR_FLOAT) {
|
||||||
|
abort = set_ref_in_item(ctx, copyID, NULL, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return abort;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mark the context of the quickfix list and the location lists (if present) as
|
||||||
|
/// "in use". So that garabage collection doesn't free the context.
|
||||||
|
bool set_ref_in_quickfix(int copyID)
|
||||||
|
{
|
||||||
|
bool abort = mark_quickfix_ctx(&ql_info, copyID);
|
||||||
|
if (abort) {
|
||||||
|
return abort;
|
||||||
|
}
|
||||||
|
|
||||||
|
FOR_ALL_TAB_WINDOWS(tp, win) {
|
||||||
|
if (win->w_llist != NULL) {
|
||||||
|
abort = mark_quickfix_ctx(win->w_llist, copyID);
|
||||||
|
if (abort) {
|
||||||
|
return abort;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return abort;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ":[range]cbuffer [bufnr]" command.
|
* ":[range]cbuffer [bufnr]" command.
|
||||||
* ":[range]caddbuffer [bufnr]" command.
|
* ":[range]caddbuffer [bufnr]" command.
|
||||||
|
@@ -1754,6 +1754,69 @@ func Xproperty_tests(cchar)
|
|||||||
if a:cchar == 'l'
|
if a:cchar == 'l'
|
||||||
call assert_equal({}, getloclist(99, {'title': 1}))
|
call assert_equal({}, getloclist(99, {'title': 1}))
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
" Context related tests
|
||||||
|
call g:Xsetlist([], 'a', {'context':[1,2,3]})
|
||||||
|
call test_garbagecollect_now()
|
||||||
|
let d = g:Xgetlist({'context':1})
|
||||||
|
call assert_equal([1,2,3], d.context)
|
||||||
|
call g:Xsetlist([], 'a', {'context':{'color':'green'}})
|
||||||
|
let d = g:Xgetlist({'context':1})
|
||||||
|
call assert_equal({'color':'green'}, d.context)
|
||||||
|
call g:Xsetlist([], 'a', {'context':"Context info"})
|
||||||
|
let d = g:Xgetlist({'context':1})
|
||||||
|
call assert_equal("Context info", d.context)
|
||||||
|
call g:Xsetlist([], 'a', {'context':246})
|
||||||
|
let d = g:Xgetlist({'context':1})
|
||||||
|
call assert_equal(246, d.context)
|
||||||
|
if a:cchar == 'l'
|
||||||
|
" Test for copying context across two different location lists
|
||||||
|
new | only
|
||||||
|
let w1_id = win_getid()
|
||||||
|
let l = [1]
|
||||||
|
call setloclist(0, [], 'a', {'context':l})
|
||||||
|
new
|
||||||
|
let w2_id = win_getid()
|
||||||
|
call add(l, 2)
|
||||||
|
call assert_equal([1, 2], getloclist(w1_id, {'context':1}).context)
|
||||||
|
call assert_equal([1, 2], getloclist(w2_id, {'context':1}).context)
|
||||||
|
unlet! l
|
||||||
|
call assert_equal([1, 2], getloclist(w2_id, {'context':1}).context)
|
||||||
|
only
|
||||||
|
call setloclist(0, [], 'f')
|
||||||
|
call assert_equal({}, getloclist(0, {'context':1}))
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Test for changing the context of previous quickfix lists
|
||||||
|
call g:Xsetlist([], 'f')
|
||||||
|
Xexpr "One"
|
||||||
|
Xexpr "Two"
|
||||||
|
Xexpr "Three"
|
||||||
|
call g:Xsetlist([], ' ', {'context' : [1], 'nr' : 1})
|
||||||
|
call g:Xsetlist([], ' ', {'context' : [2], 'nr' : 2})
|
||||||
|
" Also, check for setting the context using quickfix list number zero.
|
||||||
|
call g:Xsetlist([], ' ', {'context' : [3], 'nr' : 0})
|
||||||
|
call test_garbagecollect_now()
|
||||||
|
let l = g:Xgetlist({'nr' : 1, 'context' : 1})
|
||||||
|
call assert_equal([1], l.context)
|
||||||
|
let l = g:Xgetlist({'nr' : 2, 'context' : 1})
|
||||||
|
call assert_equal([2], l.context)
|
||||||
|
let l = g:Xgetlist({'nr' : 3, 'context' : 1})
|
||||||
|
call assert_equal([3], l.context)
|
||||||
|
|
||||||
|
" Test for changing the context through reference and for garbage
|
||||||
|
" collection of quickfix context
|
||||||
|
let l = ["red"]
|
||||||
|
call g:Xsetlist([], ' ', {'context' : l})
|
||||||
|
call add(l, "blue")
|
||||||
|
let x = g:Xgetlist({'context' : 1})
|
||||||
|
call add(x.context, "green")
|
||||||
|
call assert_equal(["red", "blue", "green"], l)
|
||||||
|
call assert_equal(["red", "blue", "green"], x.context)
|
||||||
|
unlet l
|
||||||
|
call test_garbagecollect_now()
|
||||||
|
let m = g:Xgetlist({'context' : 1})
|
||||||
|
call assert_equal(["red", "blue", "green"], m.context)
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func Test_qf_property()
|
func Test_qf_property()
|
||||||
@@ -2023,3 +2086,19 @@ func Test_qf_free()
|
|||||||
call XfreeTests('c')
|
call XfreeTests('c')
|
||||||
call XfreeTests('l')
|
call XfreeTests('l')
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
" Test for buffer overflow when parsing lines and adding new entries to
|
||||||
|
" the quickfix list.
|
||||||
|
func Test_bufoverflow()
|
||||||
|
set efm=%f:%l:%m
|
||||||
|
cgetexpr ['File1:100:' . repeat('x', 1025)]
|
||||||
|
|
||||||
|
set efm=%+GCompiler:\ %.%#,%f:%l:%m
|
||||||
|
cgetexpr ['Compiler: ' . repeat('a', 1015), 'File1:10:Hello World']
|
||||||
|
|
||||||
|
set efm=%DEntering\ directory\ %f,%f:%l:%m
|
||||||
|
cgetexpr ['Entering directory ' . repeat('a', 1006),
|
||||||
|
\ 'File1:10:Hello World']
|
||||||
|
set efm&vim
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user