changeset 29896:c554ac4c17c3 v9.0.0286

patch 9.0.0286: using freed memory when location list changed in autocmd Commit: https://github.com/vim/vim/commit/6d24a51b94beb1991cddce221f90b455e2d50db7 Author: Yegappan Lakshmanan <yegappan@yahoo.com> Date: Sat Aug 27 20:59:57 2022 +0100 patch 9.0.0286: using freed memory when location list changed in autocmd Problem: Using freed memory when location list changed in autocmd. Solution: Return QF_ABORT and handle it. (Yegappan Lakshmanan, closes #10993)
author Bram Moolenaar <Bram@vim.org>
date Sat, 27 Aug 2022 22:15:02 +0200
parents e672be81c45a
children b33b261218e8
files src/quickfix.c src/testdir/test_quickfix.vim src/version.c
diffstat 3 files changed, 38 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/src/quickfix.c
+++ b/src/quickfix.c
@@ -594,6 +594,7 @@ enum {
     QF_NOMEM = 3,
     QF_IGNORE_LINE = 4,
     QF_MULTISCAN = 5,
+    QF_ABORT = 6
 };
 
 /*
@@ -3153,7 +3154,7 @@ qf_jump_to_usable_window(int qf_fnum, in
 /*
  * Edit the selected file or help file.
  * Returns OK if successfully edited the file, FAIL on failing to open the
- * buffer and NOTDONE if the quickfix/location list was freed by an autocmd
+ * buffer and QF_ABORT if the quickfix/location list was freed by an autocmd
  * when opening the buffer.
  */
     static int
@@ -3199,14 +3200,14 @@ qf_jump_edit_buffer(
 	{
 	    emsg(_(e_current_window_was_closed));
 	    *opened_window = FALSE;
-	    return NOTDONE;
+	    return QF_ABORT;
 	}
     }
 
     if (qfl_type == QFLT_QUICKFIX && !qflist_valid(NULL, save_qfid))
     {
 	emsg(_(e_current_quickfix_list_was_changed));
-	return NOTDONE;
+	return QF_ABORT;
     }
 
     // Check if the list was changed.  The pointers may happen to be identical,
@@ -3219,7 +3220,7 @@ qf_jump_edit_buffer(
 	    emsg(_(e_current_quickfix_list_was_changed));
 	else
 	    emsg(_(e_current_location_list_was_changed));
-	return NOTDONE;
+	return QF_ABORT;
     }
 
     return retval;
@@ -3317,7 +3318,8 @@ qf_jump_print_msg(
  * a new window.
  * Returns OK if successfully jumped or opened a window. Returns FAIL if not
  * able to jump/open a window.  Returns NOTDONE if a file is not associated
- * with the entry.
+ * with the entry.  Returns QF_ABORT if the quickfix/location list was modified
+ * by an autocmd.
  */
     static int
 qf_jump_open_window(
@@ -3344,7 +3346,7 @@ qf_jump_open_window(
 	    emsg(_(e_current_quickfix_list_was_changed));
 	else
 	    emsg(_(e_current_location_list_was_changed));
-	return FAIL;
+	return QF_ABORT;
     }
 
     // If currently in the quickfix window, find another window to show the
@@ -3368,7 +3370,7 @@ qf_jump_open_window(
 	    emsg(_(e_current_quickfix_list_was_changed));
 	else
 	    emsg(_(e_current_location_list_was_changed));
-	return FAIL;
+	return QF_ABORT;
     }
 
     return OK;
@@ -3379,7 +3381,7 @@ qf_jump_open_window(
  * particular line/column, adjust the folds and display a message about the
  * jump.
  * Returns OK on success and FAIL on failing to open the file/buffer.  Returns
- * NOTDONE if the quickfix/location list is freed by an autocmd when opening
+ * QF_ABORT if the quickfix/location list is freed by an autocmd when opening
  * the file.
  */
     static int
@@ -3508,14 +3510,20 @@ qf_jump_newwin(qf_info_T	*qi,
     retval = qf_jump_open_window(qi, qf_ptr, newwin, &opened_window);
     if (retval == FAIL)
 	goto failed;
+    if (retval == QF_ABORT)
+    {
+	qi = NULL;
+	qf_ptr = NULL;
+	goto theend;
+    }
     if (retval == NOTDONE)
 	goto theend;
 
     retval = qf_jump_to_buffer(qi, qf_index, qf_ptr, forceit, prev_winid,
 				  &opened_window, old_KeyTyped, print_message);
-    if (retval == NOTDONE)
-    {
-	// Quickfix/location list is freed by an autocmd
+    if (retval == QF_ABORT)
+    {
+	// Quickfix/location list was modified by an autocmd
 	qi = NULL;
 	qf_ptr = NULL;
     }
--- a/src/testdir/test_quickfix.vim
+++ b/src/testdir/test_quickfix.vim
@@ -6363,5 +6363,22 @@ func Test_quickfixtextfunc_recursive()
   cclose
 endfunc
 
+" Test for replacing the location list from an autocmd. This used to cause a
+" read from freed memory.
+func Test_loclist_replace_autocmd()
+  %bw!
+  call setloclist(0, [], 'f')
+  let s:bufnr = bufnr()
+  cal setloclist(0, [{'0': 0, '': ''}])
+  au BufEnter * cal setloclist(1, [{'t': ''}, {'bufnr': s:bufnr}], 'r')
+  lopen
+  try
+    exe "norm j\<CR>"
+  catch
+  endtry
+  lnext
+  %bw!
+  call setloclist(0, [], 'f')
+endfunc
 
 " vim: shiftwidth=2 sts=2 expandtab
--- a/src/version.c
+++ b/src/version.c
@@ -708,6 +708,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    286,
+/**/
     285,
 /**/
     284,