Hi Yegappan and list,
2016-3-23(Wed) 14:39:31 UTC+9 h_east:
> Hi Yegappan,
>
> 2016-3-23(Wed) 14:02:53 UTC+9 [email protected]:
> > Hi,
> >
> > On Mon, Mar 21, 2016 at 2:45 AM, Dominique Pellé
> > <[email protected]> wrote:
> > > Hi
> > >
> > > afl-fuzz found another crash with use of freed memory in vim-7.4.1627
> > > (and older) in quickfix code. This is a different bug that the one fixed
> > > recently in Vim-7.4.1592:
> > >
> >
> > The attached patch fixes this issue. These issues are caused by autocmds
> > modifying the location list while the location list is being used.
>
> This issue also occurs with the quickfix.
>
> ]$ vim -Nu NONE -S crash_qf.vim
> Vim: Caught deadly signal SEGV
>
> Vim: Finished.
> Segmentation fault (core dumped)
>
>
> PS
> I think we should abort even if `qi->qf_curlist` has changed.
>
> I'm sorry. In fact, I have had already written a patch.
> But did not yet been submitted.
> I'll send patch later.
A patch is attached.
Please check it.
Yegappan>
I have modified to respect your patch.
Thank you for the nice patch.
After all, You are the quickfix wizard :-)
--
Best regards,
Hirohito Higashi (a.k.a. h_east)
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.
diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt
index 0ca314d..fb23552 100644
--- a/runtime/doc/quickfix.txt
+++ b/runtime/doc/quickfix.txt
@@ -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 06e50da..b95d1a7 100644
--- a/src/quickfix.c
+++ b/src/quickfix.c
@@ -1413,6 +1413,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
* if dir == BACKWARD go "errornr" valid entries backward
@@ -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;
+ }
+ 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 07c465d..667ece4 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("<amatch>"))
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