Mercurial > vim
changeset 22256:c3c9830c7cdc v8.2.1677
patch 8.2.1677: memory access errors when calling setloclist() in autocommand
Commit: https://github.com/vim/vim/commit/4d170af0a9379da64d67dc3fa7cc7297956c6f52
Author: Bram Moolenaar <Bram@vim.org>
Date: Sun Sep 13 22:21:22 2020 +0200
patch 8.2.1677: memory access errors when calling setloclist() in autocommand
Problem: Memory access errors when calling setloclist() in an autocommand.
Solution: Give an error if the list was changed unexpectedly. (closes https://github.com/vim/vim/issues/6946)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sun, 13 Sep 2020 22:30:03 +0200 |
parents | 8b74d01f1dd6 |
children | 595568bd6795 |
files | src/quickfix.c src/testdir/test_quickfix.vim src/version.c |
diffstat | 3 files changed, 62 insertions(+), 5 deletions(-) [+] |
line wrap: on
line diff
--- a/src/quickfix.c +++ b/src/quickfix.c @@ -216,7 +216,9 @@ static char_u *e_no_more_items = (char_u static char_u *qf_last_bufname = NULL; static bufref_T qf_last_bufref = {NULL, 0, 0}; -static char *e_loc_list_changed = +static char *e_current_quickfix_list_was_changed = + N_("E925: Current quickfix list was changed"); +static char *e_current_location_list_was_changed = N_("E926: Current location list was changed"); /* @@ -3108,6 +3110,7 @@ qf_jump_edit_buffer( int *opened_window) { qf_list_T *qfl = qf_get_curlist(qi); + int old_changedtick = qfl->qf_changedtick; qfltype_T qfl_type = qfl->qfl_type; int retval = OK; int old_qf_curlist = qi->qf_curlist; @@ -3146,17 +3149,20 @@ qf_jump_edit_buffer( if (qfl_type == QFLT_QUICKFIX && !qflist_valid(NULL, save_qfid)) { - emsg(_("E925: Current quickfix was changed")); + emsg(_(e_current_quickfix_list_was_changed)); return NOTDONE; } + // Check if the list was changed. The pointers may happen to be identical, + // thus also check qf_changedtick. if (old_qf_curlist != qi->qf_curlist + || old_changedtick != qfl->qf_changedtick || !is_qf_entry_present(qfl, qf_ptr)) { if (qfl_type == QFLT_QUICKFIX) - emsg(_("E925: Current quickfix was changed")); + emsg(_(e_current_quickfix_list_was_changed)); else - emsg(_(e_loc_list_changed)); + emsg(_(e_current_location_list_was_changed)); return NOTDONE; } @@ -3264,10 +3270,25 @@ qf_jump_open_window( int newwin, int *opened_window) { + qf_list_T *qfl = qf_get_curlist(qi); + int old_changedtick = qfl->qf_changedtick; + int old_qf_curlist = qi->qf_curlist; + qfltype_T qfl_type = qfl->qfl_type; + // For ":helpgrep" find a help window or open one. if (qf_ptr->qf_type == 1 && (!bt_help(curwin->w_buffer) || cmdmod.tab != 0)) if (jump_to_help_window(qi, newwin, opened_window) == FAIL) return FAIL; + if (old_qf_curlist != qi->qf_curlist + || old_changedtick != qfl->qf_changedtick + || !is_qf_entry_present(qfl, qf_ptr)) + { + if (qfl_type == QFLT_QUICKFIX) + emsg(_(e_current_quickfix_list_was_changed)); + else + emsg(_(e_current_location_list_was_changed)); + return FAIL; + } // If currently in the quickfix window, find another window to show the // file in. @@ -3282,6 +3303,16 @@ qf_jump_open_window( opened_window) == FAIL) return FAIL; } + if (old_qf_curlist != qi->qf_curlist + || old_changedtick != qfl->qf_changedtick + || !is_qf_entry_present(qfl, qf_ptr)) + { + if (qfl_type == QFLT_QUICKFIX) + emsg(_(e_current_quickfix_list_was_changed)); + else + emsg(_(e_current_location_list_was_changed)); + return FAIL; + } return OK; } @@ -5834,7 +5865,7 @@ vgr_qflist_valid( if (wp != NULL) { // An autocmd has freed the location list. - emsg(_(e_loc_list_changed)); + emsg(_(e_current_location_list_was_changed)); return FALSE; } else
--- a/src/testdir/test_quickfix.vim +++ b/src/testdir/test_quickfix.vim @@ -1430,6 +1430,30 @@ func Test_quickfix_was_changed_by_autocm call XquickfixChangedByAutocmd('l') endfunc +func Test_setloclist_in_autocommand() + call writefile(['test1', 'test2'], 'Xfile') + edit Xfile + let s:bufnr = bufnr() + call setloclist(1, + \ [{'bufnr' : s:bufnr, 'lnum' : 1, 'text' : 'test1'}, + \ {'bufnr' : s:bufnr, 'lnum' : 2, 'text' : 'test2'}]) + + augroup Test_LocList + au! + autocmd BufEnter * call setloclist(1, + \ [{'bufnr' : s:bufnr, 'lnum' : 1, 'text' : 'test1'}, + \ {'bufnr' : s:bufnr, 'lnum' : 2, 'text' : 'test2'}], 'r') + augroup END + + lopen + call assert_fails('exe "normal j\<CR>"', 'E926:') + + augroup Test_LocList + au! + augroup END + call delete('Xfile') +endfunc + func Test_caddbuffer_to_empty() helpgr quickfix call setqflist([], 'r')