@@ -144,6 +144,7 @@ static int qf_get_fnum(qf_info_T *qi, int qf_idx, char_u *, char_u *);
144144static char_u * qf_push_dir (char_u * , struct dir_stack_T * * , int is_file_stack );
145145static char_u * qf_pop_dir (struct dir_stack_T * * );
146146static char_u * qf_guess_filepath (qf_info_T * qi , int qf_idx , char_u * );
147+ static int qflist_valid (win_T * wp , int_u qf_id );
147148static void qf_fmt_text (char_u * text , char_u * buf , int bufsize );
148149static void qf_clean_dir_stack (struct dir_stack_T * * );
149150static int qf_win_pos_update (qf_info_T * qi , int old_qf_index );
@@ -177,6 +178,9 @@ static qf_info_T *ll_get_or_alloc_list(win_T *);
177178static char_u * qf_last_bufname = NULL ;
178179static bufref_T qf_last_bufref = {NULL , 0 , 0 };
179180
181+ static char * e_loc_list_changed =
182+ N_ ("E926: Current location list was changed" );
183+
180184/*
181185 * Read the errorfile "efile" into memory, line by line, building the error
182186 * list. Set the error list's title to qf_title.
@@ -1927,6 +1931,29 @@ qf_guess_filepath(qf_info_T *qi, int qf_idx, char_u *filename)
19271931 return ds_ptr == NULL ? NULL : ds_ptr -> dirname ;
19281932}
19291933
1934+ /*
1935+ * Returns TRUE if a quickfix/location list with the given identifier exists.
1936+ */
1937+ static int
1938+ qflist_valid (win_T * wp , int_u qf_id )
1939+ {
1940+ qf_info_T * qi = & ql_info ;
1941+ int i ;
1942+
1943+ if (wp != NULL )
1944+ {
1945+ qi = GET_LOC_LIST (wp ); /* Location list */
1946+ if (qi == NULL )
1947+ return FALSE;
1948+ }
1949+
1950+ for (i = 0 ; i < qi -> qf_listcount ; ++ i )
1951+ if (qi -> qf_lists [i ].qf_id == qf_id )
1952+ return TRUE;
1953+
1954+ return FALSE;
1955+ }
1956+
19301957/*
19311958 * When loading a file from the quickfix, the auto commands may modify it.
19321959 * This may invalidate the current quickfix entry. This function checks
@@ -2343,22 +2370,36 @@ qf_jump_edit_buffer(
23432370 else
23442371 {
23452372 int old_qf_curlist = qi -> qf_curlist ;
2373+ int save_qfid = qi -> qf_lists [qi -> qf_curlist ].qf_id ;
23462374
23472375 retval = buflist_getfile (qf_ptr -> qf_fnum ,
23482376 (linenr_T )1 , GETF_SETMARK | GETF_SWITCH , forceit );
2349- if (qi != & ql_info && !win_valid_any_tab (oldwin ))
2377+
2378+ if (qi != & ql_info )
23502379 {
2351- EMSG (_ ("E924: Current window was closed" ));
2352- * abort = TRUE;
2353- * opened_window = FALSE;
2380+ /*
2381+ * Location list. Check whether the associated window is still
2382+ * present and the list is still valid.
2383+ */
2384+ if (!win_valid_any_tab (oldwin ))
2385+ {
2386+ EMSG (_ ("E924: Current window was closed" ));
2387+ * abort = TRUE;
2388+ * opened_window = FALSE;
2389+ }
2390+ else if (!qflist_valid (oldwin , save_qfid ))
2391+ {
2392+ EMSG (_ (e_loc_list_changed ));
2393+ * abort = TRUE;
2394+ }
23542395 }
23552396 else if (old_qf_curlist != qi -> qf_curlist
23562397 || !is_qf_entry_present (qi , qf_ptr ))
23572398 {
23582399 if (qi == & ql_info )
23592400 EMSG (_ ("E925: Current quickfix was changed" ));
23602401 else
2361- EMSG (_ ("E926: Current location list was changed" ));
2402+ EMSG (_ (e_loc_list_changed ));
23622403 * abort = TRUE;
23632404 }
23642405
@@ -4065,6 +4106,7 @@ ex_cfile(exarg_T *eap)
40654106 qf_info_T * qi = & ql_info ;
40664107#ifdef FEAT_AUTOCMD
40674108 char_u * au_name = NULL ;
4109+ int save_qfid ;
40684110#endif
40694111 int res ;
40704112
@@ -4122,8 +4164,15 @@ ex_cfile(exarg_T *eap)
41224164 if (res >= 0 && qi != NULL )
41234165 qf_list_changed (qi , qi -> qf_curlist );
41244166#ifdef FEAT_AUTOCMD
4167+ save_qfid = qi -> qf_lists [qi -> qf_curlist ].qf_id ;
41254168 if (au_name != NULL )
41264169 apply_autocmds (EVENT_QUICKFIXCMDPOST , au_name , NULL , FALSE, curbuf );
4170+ /*
4171+ * Autocmd might have freed the quickfix/location list. Check whether it is
4172+ * still valid
4173+ */
4174+ if (!qflist_valid (wp , save_qfid ))
4175+ return ;
41274176#endif
41284177 if (res > 0 && (eap -> cmdidx == CMD_cfile || eap -> cmdidx == CMD_lfile ))
41294178 {
@@ -4149,8 +4198,11 @@ ex_vimgrep(exarg_T *eap)
41494198 char_u * p ;
41504199 int fi ;
41514200 qf_info_T * qi = & ql_info ;
4201+ int loclist_cmd = FALSE;
41524202#ifdef FEAT_AUTOCMD
4203+ int_u save_qfid ;
41534204 qfline_T * cur_qf_start ;
4205+ win_T * wp ;
41544206#endif
41554207 long lnum ;
41564208 buf_T * buf ;
@@ -4204,6 +4256,7 @@ ex_vimgrep(exarg_T *eap)
42044256 qi = ll_get_or_alloc_list (curwin );
42054257 if (qi == NULL )
42064258 return ;
4259+ loclist_cmd = TRUE;
42074260 }
42084261
42094262 if (eap -> addr_count > 0 )
@@ -4274,8 +4327,9 @@ ex_vimgrep(exarg_T *eap)
42744327 mch_dirname (dirname_start , MAXPATHL );
42754328
42764329#ifdef FEAT_AUTOCMD
4277- /* Remember the value of qf_start, so that we can check for autocommands
4278- * changing the current quickfix list. */
4330+ /* Remember the current values of the quickfix list and qf_start, so that
4331+ * we can check for autocommands changing the current quickfix list. */
4332+ save_qfid = qi -> qf_lists [qi -> qf_curlist ].qf_id ;
42794333 cur_qf_start = qi -> qf_lists [qi -> qf_curlist ].qf_start ;
42804334#endif
42814335
@@ -4335,6 +4389,18 @@ ex_vimgrep(exarg_T *eap)
43354389 using_dummy = FALSE;
43364390
43374391#ifdef FEAT_AUTOCMD
4392+ if (loclist_cmd )
4393+ {
4394+ /*
4395+ * Verify that the location list is still valid. An autocmd might
4396+ * have freed the location list.
4397+ */
4398+ if (!qflist_valid (curwin , save_qfid ))
4399+ {
4400+ EMSG (_ (e_loc_list_changed ));
4401+ goto theend ;
4402+ }
4403+ }
43384404 if (cur_qf_start != qi -> qf_lists [qi -> qf_curlist ].qf_start )
43394405 {
43404406 int idx ;
@@ -4491,6 +4557,13 @@ ex_vimgrep(exarg_T *eap)
44914557 if (au_name != NULL )
44924558 apply_autocmds (EVENT_QUICKFIXCMDPOST , au_name ,
44934559 curbuf -> b_fname , TRUE, curbuf );
4560+ /*
4561+ * The QuickFixCmdPost autocmd may free the quickfix list. Check the list
4562+ * is still valid.
4563+ */
4564+ wp = loclist_cmd ? curwin : NULL ;
4565+ if (!qflist_valid (wp , save_qfid ))
4566+ goto theend ;
44944567#endif
44954568
44964569 /* Jump to first match. */
@@ -5543,7 +5616,8 @@ ex_cbuffer(exarg_T *eap)
55435616#endif
55445617
55455618 /* Must come after autocommands. */
5546- if (eap -> cmdidx == CMD_lbuffer || eap -> cmdidx == CMD_lgetbuffer
5619+ if (eap -> cmdidx == CMD_lbuffer
5620+ || eap -> cmdidx == CMD_lgetbuffer
55475621 || eap -> cmdidx == CMD_laddbuffer )
55485622 {
55495623 qi = ll_get_or_alloc_list (curwin );
@@ -5614,14 +5688,6 @@ ex_cexpr(exarg_T *eap)
56145688#endif
56155689 int res ;
56165690
5617- if (eap -> cmdidx == CMD_lexpr || eap -> cmdidx == CMD_lgetexpr
5618- || eap -> cmdidx == CMD_laddexpr )
5619- {
5620- qi = ll_get_or_alloc_list (curwin );
5621- if (qi == NULL )
5622- return ;
5623- }
5624-
56255691#ifdef FEAT_AUTOCMD
56265692 switch (eap -> cmdidx )
56275693 {
@@ -5643,6 +5709,15 @@ ex_cexpr(exarg_T *eap)
56435709 }
56445710#endif
56455711
5712+ if (eap -> cmdidx == CMD_lexpr
5713+ || eap -> cmdidx == CMD_lgetexpr
5714+ || eap -> cmdidx == CMD_laddexpr )
5715+ {
5716+ qi = ll_get_or_alloc_list (curwin );
5717+ if (qi == NULL )
5718+ return ;
5719+ }
5720+
56465721 /* Evaluate the expression. When the result is a string or a list we can
56475722 * use it to fill the errorlist. */
56485723 tv = eval_expr (eap -> arg , NULL );
0 commit comments