diff options
author | James McCoy <jamessan@jamessan.com> | 2017-12-19 19:21:30 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-12-19 19:21:30 -0500 |
commit | aa951b14893d8a30ec3bad6fb4b7064ccda16d5c (patch) | |
tree | a0bc8eade01a25a5dbbb69bc20930e84ac221030 /src | |
parent | 53a530b2f54e69adb52d32718edf36df7c0b1b5b (diff) | |
parent | 190814bdae496c0ce4dfb524f9bb5ee7a09b4f60 (diff) | |
download | rneovim-aa951b14893d8a30ec3bad6fb4b7064ccda16d5c.tar.gz rneovim-aa951b14893d8a30ec3bad6fb4b7064ccda16d5c.tar.bz2 rneovim-aa951b14893d8a30ec3bad6fb4b7064ccda16d5c.zip |
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
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/eval.c | 2 | ||||
-rw-r--r-- | src/nvim/quickfix.c | 84 | ||||
-rw-r--r-- | src/nvim/testdir/test_quickfix.vim | 79 |
3 files changed, 161 insertions, 4 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 1461ddb8f9..2355c8c813 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -5173,6 +5173,8 @@ bool garbage_collect(bool testing) ABORTING(set_ref_list)(sub.additional_elements, copyID); } + ABORTING(set_ref_in_quickfix)(copyID); + bool did_free = false; if (!abort) { // 2. Free lists and dictionaries that are not referenced. diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index d77cec4fd8..c5d03e73f1 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -85,6 +85,7 @@ typedef struct qf_list_S { int qf_nonevalid; // TRUE if not a single valid entry found char_u *qf_title; // title derived from the command that created // the error list + typval_T *qf_ctx; // context set by setqflist/setloclist } qf_list_T; struct qf_info_S { @@ -800,7 +801,7 @@ restofline: fields->type = *regmatch.startp[i]; } if (fmt_ptr->flags == '+' && !qi->qf_multiscan) { // %+ - if (linelen > fields->errmsglen) { + if (linelen >= fields->errmsglen) { // linelen + null terminator fields->errmsg = xrealloc(fields->errmsg, linelen + 1); fields->errmsglen = linelen + 1; @@ -811,7 +812,7 @@ restofline: continue; } len = (size_t)(regmatch.endp[i] - regmatch.startp[i]); - if (len > fields->errmsglen) { + if (len >= fields->errmsglen) { // len + null terminator fields->errmsg = xrealloc(fields->errmsg, len + 1); fields->errmsglen = len + 1; @@ -888,7 +889,7 @@ restofline: fields->namebuf[0] = NUL; // no match found, remove file name fields->lnum = 0; // don't jump to this line fields->valid = false; - if (linelen > fields->errmsglen) { + if (linelen >= fields->errmsglen) { // linelen + null terminator fields->errmsg = xrealloc(fields->errmsg, linelen + 1); fields->errmsglen = linelen + 1; @@ -1409,6 +1410,13 @@ void copy_loclist(win_T *from, win_T *to) else 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) { qfline_T *from_qfp; 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_ptr = 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_start = NULL; qi->qf_lists[idx].qf_last = NULL; @@ -4060,6 +4070,7 @@ enum { QF_GETLIST_ITEMS = 0x2, QF_GETLIST_NR = 0x4, QF_GETLIST_WINID = 0x8, + QF_GETLIST_CONTEXT = 0x10, 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; } + if (tv_dict_find(what, S_LEN("context")) != NULL) { + flags |= QF_GETLIST_CONTEXT; + } + if (flags & QF_GETLIST_TITLE) { char_u *t = qi->qf_lists[qf_idx].qf_title; 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; } @@ -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) { // Use the specified quickfix/location list if (di->di_tv.v_type == VAR_NUMBER) { - qf_idx = (int)di->di_tv.vval.v_number - 1; + // for zero use the current list + if (di->di_tv.vval.v_number != 0) { + qf_idx = (int)di->di_tv.vval.v_number - 1; + } if (qf_idx < 0 || qf_idx >= qi->qf_listcount) { 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; } @@ -4362,6 +4402,42 @@ int set_errorlist(win_T *wp, list_T *list, int action, char_u *title, 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]caddbuffer [bufnr]" command. diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index dd64e37ce3..30023dddc9 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -1754,6 +1754,69 @@ func Xproperty_tests(cchar) if a:cchar == 'l' call assert_equal({}, getloclist(99, {'title': 1})) 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 func Test_qf_property() @@ -2023,3 +2086,19 @@ func Test_qf_free() call XfreeTests('c') call XfreeTests('l') 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 + |