Hi,

On Mon, Mar 21, 2016 at 2:45 AM, Dominique Pellé
<dominique.pe...@gmail.com> 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 vim_dev+unsubscr...@googlegroups.com.
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

Reply via email to