From ffec3c53496d49668669deabc0724ec78e2274fd Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 23 Mar 2016 20:55:42 +0100 Subject: [PATCH 1/2] patch 7.4.1640 Problem: Crash when an autocommand changes a quickfix list. (Dominique) Solution: Check wether an entry is still valid. (Yegappan Lakshmanan, Hirohito Higashi) --- runtime/doc/quickfix.txt | 6 ++++- src/quickfix.c | 47 +++++++++++++++++++++++++++++++++-- src/testdir/test_quickfix.vim | 44 +++++++++++++++++++++++++++++++- src/version.c | 2 ++ 4 files changed, 95 insertions(+), 4 deletions(-) diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt index 0ca314db1a..a4c120863c 100644 --- a/runtime/doc/quickfix.txt +++ b/runtime/doc/quickfix.txt @@ -1,4 +1,4 @@ -*quickfix.txt* For Vim version 7.4. Last change: 2016 Mar 19 +*quickfix.txt* For Vim version 7.4. Last change: 2016 Mar 23 VIM REFERENCE MANUAL by Bram Moolenaar @@ -60,6 +60,10 @@ command with 'l'. If the current window was closed by an |autocommand| while processing a location list command, it will be aborted. + *E925* *E926* +If the current quickfix or location list was changed by an |autocommand| while +processing a quickfix or location list command, it will be aborted. + *:cc* :cc[!] [nr] Display error [nr]. If [nr] is omitted, the same error is displayed again. Without [!] this doesn't diff --git a/src/quickfix.c b/src/quickfix.c index 06e50da47d..a2506e1a32 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -1412,6 +1412,33 @@ qf_guess_filepath(char_u *filename) } +/* + * When loading a file from the quickfix, the auto commands may modify it. + * This may invalidate the current quickfix entry. This function checks + * whether a entry is still present in the quickfix. + * Similar to location list. + */ + static int +is_qf_entry_present(qf_info_T *qi, qfline_T *qf_ptr) +{ + qf_list_T *qfl; + qfline_T *qfp; + int i; + + qfl = &qi->qf_lists[qi->qf_curlist]; + + /* Search for the entry in the current list */ + for (i = 0, qfp = qfl->qf_start; i < qfl->qf_count; + ++i, qfp = qfp->qf_next) + if (qfp == qf_ptr) + break; + + if (i == qfl->qf_count) /* Entry is not found */ + return FALSE; + + return TRUE; +} + /* * jump to a quickfix line * if dir == FORWARD go "errornr" valid entries forward @@ -1794,18 +1821,34 @@ win_found: } else { + int old_qf_curlist = qi->qf_curlist; + int is_abort = FALSE; + ok = buflist_getfile(qf_ptr->qf_fnum, (linenr_T)1, GETF_SETMARK | GETF_SWITCH, forceit); if (qi != &ql_info && !win_valid(oldwin)) { EMSG(_("E924: Current window was closed")); + is_abort = TRUE; + opened_window = FALSE; + } + else if (old_qf_curlist != qi->qf_curlist + || !is_qf_entry_present(qi, qf_ptr)) + { + if (qi == &ql_info) + EMSG(_("E925: Current quickfix was changed")); + else + EMSG(_("E926: Current location list was changed")); + is_abort = TRUE; + } + + if (is_abort) + { ok = FALSE; qi = NULL; qf_ptr = NULL; - opened_window = FALSE; } } - } if (ok == OK) diff --git a/src/testdir/test_quickfix.vim b/src/testdir/test_quickfix.vim index 07c465d8d3..667ece4e67 100644 --- a/src/testdir/test_quickfix.vim +++ b/src/testdir/test_quickfix.vim @@ -504,7 +504,7 @@ function Test_locationlist_curwin_was_closed() autocmd BufReadCmd t call R(expand("")) augroup END - function R(n) + function! R(n) quit endfunc @@ -637,3 +637,45 @@ function! Test_efm1() call delete('Xerrorfile2') call delete('Xtestfile') endfunction + +function XquickfixChangedByAutocmd(cchar) + let Xolder = a:cchar . 'older' + let Xgetexpr = a:cchar . 'getexpr' + let Xrewind = a:cchar . 'rewind' + if a:cchar == 'c' + let Xsetlist = 'setqflist(' + let ErrorNr = 'E925' + function! ReadFunc() + colder + cgetexpr [] + endfunc + else + let Xsetlist = 'setloclist(0,' + let ErrorNr = 'E926' + function! ReadFunc() + lolder + lgetexpr [] + endfunc + endif + + augroup testgroup + au! + autocmd BufReadCmd t call ReadFunc() + augroup END + + bwipe! + let words = [ "a", "b" ] + let qflist = [] + for word in words + call add(qflist, {'filename': 't'}) + exec "call " . Xsetlist . "qflist, '')" + endfor + exec "call assert_fails('" . Xrewind . "', '" . ErrorNr . ":')" + + augroup! testgroup +endfunc + +function Test_quickfix_was_changed_by_autocmd() + call XquickfixChangedByAutocmd('c') + call XquickfixChangedByAutocmd('l') +endfunction diff --git a/src/version.c b/src/version.c index 6fffeeb761..c9c550a490 100644 --- a/src/version.c +++ b/src/version.c @@ -748,6 +748,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1640, /**/ 1639, /**/ From 5ca84ce4aa2832041f843e624c222bbc1f4d3e14 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 23 Mar 2016 22:28:25 +0100 Subject: [PATCH 2/2] patch 7.4.1641 Problem: Using unterminated string. Solution: Add NUL before calling vim_strsave_shellescape(). (James McCoy) --- src/eval.c | 2 ++ src/testdir/test105.in | 1 + src/testdir/test105.ok | 1 + src/version.c | 2 ++ 4 files changed, 6 insertions(+) diff --git a/src/eval.c b/src/eval.c index 990fa8c05b..9091f7972f 100644 --- a/src/eval.c +++ b/src/eval.c @@ -26439,6 +26439,8 @@ repeat: if (src[*usedlen] == ':' && src[*usedlen + 1] == 'S') { + /* vim_strsave_shellescape() needs a NUL terminated string. */ + (*fnamep)[*fnamelen] = NUL; p = vim_strsave_shellescape(*fnamep, FALSE, FALSE); if (p == NULL) return -1; diff --git a/src/testdir/test105.in b/src/testdir/test105.in index 58c4f84c0d..9921d7ed7c 100644 --- a/src/testdir/test105.in +++ b/src/testdir/test105.in @@ -35,6 +35,7 @@ STARTTEST :Put fnamemodify('abc'' ''def', ':S' ) :Put fnamemodify('abc''%''def', ':S' ) :Put fnamemodify("abc\ndef", ':S' ) +:Put expand('%:r:S') == shellescape(expand('%:r')) :set shell=tcsh :Put fnamemodify("abc\ndef", ':S' ) :$put ='vim: ts=8' diff --git a/src/testdir/test105.ok b/src/testdir/test105.ok index 5f1de5f9e6..584f0fe6a0 100644 --- a/src/testdir/test105.ok +++ b/src/testdir/test105.ok @@ -25,5 +25,6 @@ fnamemodify('abc"%"def', ':S' ) '''abc"%"def''' fnamemodify('abc'' ''def', ':S' ) '''abc''\'''' ''\''''def''' fnamemodify('abc''%''def', ':S' ) '''abc''\''''%''\''''def''' fnamemodify("abc\ndef", ':S' ) '''abc^@def''' +expand('%:r:S') == shellescape(expand('%:r')) 1 fnamemodify("abc\ndef", ':S' ) '''abc\^@def''' vim: ts=8 diff --git a/src/version.c b/src/version.c index c9c550a490..465794a0aa 100644 --- a/src/version.c +++ b/src/version.c @@ -748,6 +748,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1641, /**/ 1640, /**/