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.
- Yegappan
>
> $ cat > crash.vim <<EOF
> fun! R()
> lolder
> lgetexpr []
> endfun
>
> autocmd BufReadCmd * call R()
> let words = [ "a", "b" ]
> let qflist = []
> for word in words
> call add(qflist, {'filename': 't'})
> call setloclist(0, qflist, ' ')
> endfor
> lrewind
> EOF
>
> $ vim -u NONE -N -S crash.vim
> Vim: Caught deadly signal SEGV
>
> Vim: Finished.
> Segmentation fault
>
>
--
--
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/src/quickfix.c b/src/quickfix.c
index 06e50da..24ef119 100644
--- a/src/quickfix.c
+++ b/src/quickfix.c
@@ -1413,6 +1413,32 @@ qf_guess_filepath(char_u *filename)
}
/*
+ * When loading a file from the location list, the auto commands may modify the
+ * location list. This may invalidate the current location list entry. This
+ * function checks whether a entry is still present in the location list.
+ */
+ static int
+is_ll_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
@@ -1796,16 +1822,30 @@ win_found:
{
ok = buflist_getfile(qf_ptr->qf_fnum,
(linenr_T)1, GETF_SETMARK | GETF_SWITCH, forceit);
- if (qi != &ql_info && !win_valid(oldwin))
+ if (qi != &ql_info)
{
- EMSG(_("E924: Current window was closed"));
- ok = FALSE;
- qi = NULL;
- qf_ptr = NULL;
- opened_window = FALSE;
+ /*
+ * Location list. When loading the buffer using
+ * buflist_getfile(), autocommands are triggered which may
+ * alter the location list. Check whether the location list
+ * window and the location list are still valid.
+ */
+ if (!win_valid(oldwin))
+ {
+ EMSG(_("E924: Current window was closed"));
+ ok = FALSE;
+ qi = NULL;
+ qf_ptr = NULL;
+ opened_window = FALSE;
+ } else if (!is_ll_entry_present(qi, qf_ptr))
+ {
+ EMSG(_("E925: Location list is different"));
+ ok = FALSE;
+ qi = NULL;
+ qf_ptr = NULL;
+ }
}
}
-
}
if (ok == OK)
diff --git a/src/testdir/test_quickfix.vim b/src/testdir/test_quickfix.vim
index 07c465d..39a55cb 100644
--- a/src/testdir/test_quickfix.vim
+++ b/src/testdir/test_quickfix.vim
@@ -637,3 +637,23 @@ function! Test_efm1()
call delete('Xerrorfile2')
call delete('Xtestfile')
endfunction
+
+" Test for removing the location list while it is still in use
+function Test_locationlist_curlist_invalid()
+ fun! Reset_Loc_List()
+ lolder
+ lgetexpr []
+ endfun
+
+ autocmd BufReadCmd x call Reset_Loc_List()
+
+ let words = [ "a", "b" ]
+ let qflist = []
+ for word in words
+ call add(qflist, {'filename': 'x'})
+ call setloclist(0, qflist, ' ')
+ endfor
+ call assert_fails('lrewind', 'E925:')
+
+ autocmd! BufReadCmd
+endfunction