diff options
-rw-r--r-- | src/nvim/quickfix.c | 44 | ||||
-rw-r--r-- | src/nvim/testdir/test_quickfix.vim | 65 |
2 files changed, 96 insertions, 13 deletions
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index d364cebc9d..a65635cf5e 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -176,6 +176,7 @@ enum { QF_NOMEM = 3, QF_IGNORE_LINE = 4, QF_MULTISCAN = 5, + QF_ABORT = 6, }; /// State information used to parse lines and add entries to a quickfix/location @@ -2686,6 +2687,10 @@ static int qf_jump_to_usable_window(int qf_fnum, bool newwin, int *opened_window } /// Edit the selected file or help file. +/// @return OK if successfully edited the file. +/// FAIL on failing to open the buffer. +/// QF_ABORT if the quickfix/location list was freed by an autocmd +/// when opening the buffer. static int qf_jump_edit_buffer(qf_info_T *qi, qfline_T *qf_ptr, int forceit, int prev_winid, int *opened_window) { @@ -2719,13 +2724,13 @@ static int qf_jump_edit_buffer(qf_info_T *qi, qfline_T *qf_ptr, int forceit, int if (wp == NULL && curwin->w_llist != qi) { emsg(_("E924: Current window was closed")); *opened_window = false; - return NOTDONE; + return QF_ABORT; } } if (qfl_type == QFLT_QUICKFIX && !qflist_valid(NULL, save_qfid)) { emsg(_(e_current_quickfix_list_was_changed)); - return NOTDONE; + return QF_ABORT; } if (old_qf_curlist != qi->qf_curlist // -V560 @@ -2736,7 +2741,7 @@ static int qf_jump_edit_buffer(qf_info_T *qi, qfline_T *qf_ptr, int forceit, int } else { emsg(_(e_current_location_list_was_changed)); } - return NOTDONE; + return QF_ABORT; } return retval; @@ -2814,9 +2819,10 @@ static void qf_jump_print_msg(qf_info_T *qi, int qf_index, qfline_T *qf_ptr, buf /// Find a usable window for opening a file from the quickfix/location list. If /// a window is not found then open a new window. If 'newwin' is true, then open /// a new window. -/// Returns OK if successfully jumped or opened a window. Returns FAIL if not -/// able to jump/open a window. Returns NOTDONE if a file is not associated -/// with the entry. +/// @return OK if successfully jumped or opened a window. +/// FAIL if not able to jump/open a window. +/// NOTDONE if a file is not associated with the entry. +/// QF_ABORT if the quickfix/location list was modified by an autocmd. static int qf_jump_open_window(qf_info_T *qi, qfline_T *qf_ptr, bool newwin, int *opened_window) { qf_list_T *qfl = qf_get_curlist(qi); @@ -2838,7 +2844,7 @@ static int qf_jump_open_window(qf_info_T *qi, qfline_T *qf_ptr, bool newwin, int } else { emsg(_(e_current_location_list_was_changed)); } - return FAIL; + return QF_ABORT; } // If currently in the quickfix window, find another window to show the @@ -2863,7 +2869,7 @@ static int qf_jump_open_window(qf_info_T *qi, qfline_T *qf_ptr, bool newwin, int } else { emsg(_(e_current_location_list_was_changed)); } - return FAIL; + return QF_ABORT; } return OK; @@ -2872,9 +2878,9 @@ static int qf_jump_open_window(qf_info_T *qi, qfline_T *qf_ptr, bool newwin, int /// Edit a selected file from the quickfix/location list and jump to a /// particular line/column, adjust the folds and display a message about the /// jump. -/// Returns OK on success and FAIL on failing to open the file/buffer. Returns -/// NOTDONE if the quickfix/location list is freed by an autocmd when opening -/// the file. +/// @return OK on success and FAIL on failing to open the file/buffer. +/// QF_ABORT if the quickfix/location list is freed by an autocmd when opening +/// the file. static int qf_jump_to_buffer(qf_info_T *qi, int qf_index, qfline_T *qf_ptr, int forceit, int prev_winid, int *opened_window, int openfold, int print_message) { @@ -2968,14 +2974,19 @@ static void qf_jump_newwin(qf_info_T *qi, int dir, int errornr, int forceit, boo if (retval == FAIL) { goto failed; } + if (retval == QF_ABORT) { + qi = NULL; + qf_ptr = NULL; + goto theend; + } if (retval == NOTDONE) { goto theend; } retval = qf_jump_to_buffer(qi, qf_index, qf_ptr, forceit, prev_winid, &opened_window, old_KeyTyped, print_message); - if (retval == NOTDONE) { - // Quickfix/location list is freed by an autocmd + if (retval == QF_ABORT) { + // Quickfix/location list was modified by an autocmd qi = NULL; qf_ptr = NULL; } @@ -3984,6 +3995,12 @@ static list_T *call_qftf_func(qf_list_T *qfl, int qf_winid, long start_idx, long { Callback *cb = &qftf_cb; list_T *qftf_list = NULL; + static bool recursive = false; + + if (recursive) { + return NULL; // this doesn't work properly recursively + } + recursive = true; // If 'quickfixtextfunc' is set, then use the user-supplied function to get // the text to display. Use the local value of 'quickfixtextfunc' if it is @@ -4017,6 +4034,7 @@ static list_T *call_qftf_func(qf_list_T *qfl, int qf_winid, long start_idx, long tv_dict_unref(dict); } + recursive = false; return qftf_list; } diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index e19766775d..4802d1f188 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -5839,4 +5839,69 @@ func Test_getqflist_wiped_out_buffer() %bw! endfunc +" Test for the status message that is displayed when opening a new quickfix +" list +func Test_qflist_statusmsg() + cexpr "1\n2" + cexpr "1\n2\n3\ntest_quickfix.vim:1:msg" + call assert_equal('(4 of 4): msg', v:statusmsg) + call setqflist([], 'f') + %bw! + + " When creating a new quickfix list, if an autocmd changes the quickfix list + " in the stack, then an error message should be displayed. + augroup QF_Test + au! + au BufEnter test_quickfix.vim colder + augroup END + cexpr "1\n2" + call assert_fails('cexpr "1\n2\n3\ntest_quickfix.vim:1:msg"', 'E925:') + call setqflist([], 'f') + augroup QF_Test + au! + augroup END + %bw! + + augroup QF_Test + au! + au BufEnter test_quickfix.vim caddexpr "4" + augroup END + call assert_fails('cexpr "1\n2\n3\ntest_quickfix.vim:1:msg"', 'E925:') + call setqflist([], 'f') + augroup QF_Test + au! + augroup END + %bw! +endfunc + +func Test_quickfixtextfunc_recursive() + func s:QFTfunc(o) + cgete '0' + endfunc + copen + let &quickfixtextfunc = 's:QFTfunc' + cex "" + + let &quickfixtextfunc = '' + cclose +endfunc + +" Test for replacing the location list from an autocmd. This used to cause a +" read from freed memory. +func Test_loclist_replace_autocmd() + %bw! + call setloclist(0, [], 'f') + let s:bufnr = bufnr() + cal setloclist(0, [{'0': 0, '': ''}]) + au BufEnter * cal setloclist(1, [{'t': ''}, {'bufnr': s:bufnr}], 'r') + lopen + try + exe "norm j\<CR>" + catch + endtry + lnext + %bw! + call setloclist(0, [], 'f') +endfunc + " vim: shiftwidth=2 sts=2 expandtab |