comparison src/quickfix.c @ 13090:a0c6910e7fa4 v8.0.1420

patch 8.0.1420: accessing freed memory in vimgrep commit https://github.com/vim/vim/commit/3c09722600e3218905b5d4a7b635a9e6560f87b3 Author: Bram Moolenaar <Bram@vim.org> Date: Thu Dec 21 20:54:49 2017 +0100 patch 8.0.1420: accessing freed memory in vimgrep Problem: Accessing freed memory in vimgrep. Solution: Check that the quickfix list is still valid. (Yegappan Lakshmanan, closes #2474)
author Christian Brabandt <cb@256bit.org>
date Thu, 21 Dec 2017 21:00:06 +0100
parents a1f8939a4644
children bfa7f5b23c53
comparison
equal deleted inserted replaced
13089:5127f347a3e4 13090:a0c6910e7fa4
142 static char_u *qf_types(int, int); 142 static char_u *qf_types(int, int);
143 static int qf_get_fnum(qf_info_T *qi, int qf_idx, char_u *, char_u *); 143 static int qf_get_fnum(qf_info_T *qi, int qf_idx, char_u *, char_u *);
144 static char_u *qf_push_dir(char_u *, struct dir_stack_T **, int is_file_stack); 144 static char_u *qf_push_dir(char_u *, struct dir_stack_T **, int is_file_stack);
145 static char_u *qf_pop_dir(struct dir_stack_T **); 145 static char_u *qf_pop_dir(struct dir_stack_T **);
146 static char_u *qf_guess_filepath(qf_info_T *qi, int qf_idx, char_u *); 146 static 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);
147 static void qf_fmt_text(char_u *text, char_u *buf, int bufsize); 148 static void qf_fmt_text(char_u *text, char_u *buf, int bufsize);
148 static void qf_clean_dir_stack(struct dir_stack_T **); 149 static void qf_clean_dir_stack(struct dir_stack_T **);
149 static int qf_win_pos_update(qf_info_T *qi, int old_qf_index); 150 static int qf_win_pos_update(qf_info_T *qi, int old_qf_index);
150 static int is_qf_win(win_T *win, qf_info_T *qi); 151 static int is_qf_win(win_T *win, qf_info_T *qi);
151 static win_T *qf_find_win(qf_info_T *qi); 152 static win_T *qf_find_win(qf_info_T *qi);
174 * Looking up a buffer can be slow if there are many. Remember the last one 175 * Looking up a buffer can be slow if there are many. Remember the last one
175 * to make this a lot faster if there are multiple matches in the same file. 176 * to make this a lot faster if there are multiple matches in the same file.
176 */ 177 */
177 static char_u *qf_last_bufname = NULL; 178 static char_u *qf_last_bufname = NULL;
178 static bufref_T qf_last_bufref = {NULL, 0, 0}; 179 static bufref_T qf_last_bufref = {NULL, 0, 0};
180
181 static char *e_loc_list_changed =
182 N_("E926: Current location list was changed");
179 183
180 /* 184 /*
181 * Read the errorfile "efile" into memory, line by line, building the error 185 * Read the errorfile "efile" into memory, line by line, building the error
182 * list. Set the error list's title to qf_title. 186 * list. Set the error list's title to qf_title.
183 * Return -1 for error, number of errors for success. 187 * Return -1 for error, number of errors for success.
1926 1930
1927 return ds_ptr==NULL? NULL: ds_ptr->dirname; 1931 return ds_ptr==NULL? NULL: ds_ptr->dirname;
1928 } 1932 }
1929 1933
1930 /* 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
1957 /*
1931 * When loading a file from the quickfix, the auto commands may modify it. 1958 * When loading a file from the quickfix, the auto commands may modify it.
1932 * This may invalidate the current quickfix entry. This function checks 1959 * This may invalidate the current quickfix entry. This function checks
1933 * whether a entry is still present in the quickfix. 1960 * whether a entry is still present in the quickfix.
1934 * Similar to location list. 1961 * Similar to location list.
1935 */ 1962 */
2341 oldwin == curwin ? curwin : NULL); 2368 oldwin == curwin ? curwin : NULL);
2342 } 2369 }
2343 else 2370 else
2344 { 2371 {
2345 int old_qf_curlist = qi->qf_curlist; 2372 int old_qf_curlist = qi->qf_curlist;
2373 int save_qfid = qi->qf_lists[qi->qf_curlist].qf_id;
2346 2374
2347 retval = buflist_getfile(qf_ptr->qf_fnum, 2375 retval = buflist_getfile(qf_ptr->qf_fnum,
2348 (linenr_T)1, GETF_SETMARK | GETF_SWITCH, forceit); 2376 (linenr_T)1, GETF_SETMARK | GETF_SWITCH, forceit);
2349 if (qi != &ql_info && !win_valid_any_tab(oldwin)) 2377
2350 { 2378 if (qi != &ql_info)
2351 EMSG(_("E924: Current window was closed")); 2379 {
2352 *abort = TRUE; 2380 /*
2353 *opened_window = FALSE; 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 }
2354 } 2395 }
2355 else if (old_qf_curlist != qi->qf_curlist 2396 else if (old_qf_curlist != qi->qf_curlist
2356 || !is_qf_entry_present(qi, qf_ptr)) 2397 || !is_qf_entry_present(qi, qf_ptr))
2357 { 2398 {
2358 if (qi == &ql_info) 2399 if (qi == &ql_info)
2359 EMSG(_("E925: Current quickfix was changed")); 2400 EMSG(_("E925: Current quickfix was changed"));
2360 else 2401 else
2361 EMSG(_("E926: Current location list was changed")); 2402 EMSG(_(e_loc_list_changed));
2362 *abort = TRUE; 2403 *abort = TRUE;
2363 } 2404 }
2364 2405
2365 if (*abort) 2406 if (*abort)
2366 retval = FALSE; 2407 retval = FALSE;
4063 char_u *enc = NULL; 4104 char_u *enc = NULL;
4064 win_T *wp = NULL; 4105 win_T *wp = NULL;
4065 qf_info_T *qi = &ql_info; 4106 qf_info_T *qi = &ql_info;
4066 #ifdef FEAT_AUTOCMD 4107 #ifdef FEAT_AUTOCMD
4067 char_u *au_name = NULL; 4108 char_u *au_name = NULL;
4109 int save_qfid;
4068 #endif 4110 #endif
4069 int res; 4111 int res;
4070 4112
4071 #ifdef FEAT_AUTOCMD 4113 #ifdef FEAT_AUTOCMD
4072 switch (eap->cmdidx) 4114 switch (eap->cmdidx)
4120 if (wp != NULL) 4162 if (wp != NULL)
4121 qi = GET_LOC_LIST(wp); 4163 qi = GET_LOC_LIST(wp);
4122 if (res >= 0 && qi != NULL) 4164 if (res >= 0 && qi != NULL)
4123 qf_list_changed(qi, qi->qf_curlist); 4165 qf_list_changed(qi, qi->qf_curlist);
4124 #ifdef FEAT_AUTOCMD 4166 #ifdef FEAT_AUTOCMD
4167 save_qfid = qi->qf_lists[qi->qf_curlist].qf_id;
4125 if (au_name != NULL) 4168 if (au_name != NULL)
4126 apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, NULL, FALSE, curbuf); 4169 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;
4127 #endif 4176 #endif
4128 if (res > 0 && (eap->cmdidx == CMD_cfile || eap->cmdidx == CMD_lfile)) 4177 if (res > 0 && (eap->cmdidx == CMD_cfile || eap->cmdidx == CMD_lfile))
4129 { 4178 {
4130 qf_jump(qi, 0, 0, eap->forceit); /* display first error */ 4179 qf_jump(qi, 0, 0, eap->forceit); /* display first error */
4131 } 4180 }
4147 char_u *title; 4196 char_u *title;
4148 char_u *s; 4197 char_u *s;
4149 char_u *p; 4198 char_u *p;
4150 int fi; 4199 int fi;
4151 qf_info_T *qi = &ql_info; 4200 qf_info_T *qi = &ql_info;
4201 int loclist_cmd = FALSE;
4152 #ifdef FEAT_AUTOCMD 4202 #ifdef FEAT_AUTOCMD
4203 int_u save_qfid;
4153 qfline_T *cur_qf_start; 4204 qfline_T *cur_qf_start;
4205 win_T *wp;
4154 #endif 4206 #endif
4155 long lnum; 4207 long lnum;
4156 buf_T *buf; 4208 buf_T *buf;
4157 int duplicate_name = FALSE; 4209 int duplicate_name = FALSE;
4158 int using_dummy; 4210 int using_dummy;
4202 || eap->cmdidx == CMD_lvimgrepadd) 4254 || eap->cmdidx == CMD_lvimgrepadd)
4203 { 4255 {
4204 qi = ll_get_or_alloc_list(curwin); 4256 qi = ll_get_or_alloc_list(curwin);
4205 if (qi == NULL) 4257 if (qi == NULL)
4206 return; 4258 return;
4259 loclist_cmd = TRUE;
4207 } 4260 }
4208 4261
4209 if (eap->addr_count > 0) 4262 if (eap->addr_count > 0)
4210 tomatch = eap->line2; 4263 tomatch = eap->line2;
4211 else 4264 else
4272 /* Remember the current directory, because a BufRead autocommand that does 4325 /* Remember the current directory, because a BufRead autocommand that does
4273 * ":lcd %:p:h" changes the meaning of short path names. */ 4326 * ":lcd %:p:h" changes the meaning of short path names. */
4274 mch_dirname(dirname_start, MAXPATHL); 4327 mch_dirname(dirname_start, MAXPATHL);
4275 4328
4276 #ifdef FEAT_AUTOCMD 4329 #ifdef FEAT_AUTOCMD
4277 /* Remember the value of qf_start, so that we can check for autocommands 4330 /* Remember the current values of the quickfix list and qf_start, so that
4278 * changing the current quickfix list. */ 4331 * we can check for autocommands changing the current quickfix list. */
4332 save_qfid = qi->qf_lists[qi->qf_curlist].qf_id;
4279 cur_qf_start = qi->qf_lists[qi->qf_curlist].qf_start; 4333 cur_qf_start = qi->qf_lists[qi->qf_curlist].qf_start;
4280 #endif 4334 #endif
4281 4335
4282 seconds = (time_t)0; 4336 seconds = (time_t)0;
4283 for (fi = 0; fi < fcount && !got_int && tomatch > 0; ++fi) 4337 for (fi = 0; fi < fcount && !got_int && tomatch > 0; ++fi)
4333 else 4387 else
4334 /* Use existing, loaded buffer. */ 4388 /* Use existing, loaded buffer. */
4335 using_dummy = FALSE; 4389 using_dummy = FALSE;
4336 4390
4337 #ifdef FEAT_AUTOCMD 4391 #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 }
4338 if (cur_qf_start != qi->qf_lists[qi->qf_curlist].qf_start) 4404 if (cur_qf_start != qi->qf_lists[qi->qf_curlist].qf_start)
4339 { 4405 {
4340 int idx; 4406 int idx;
4341 4407
4342 /* Autocommands changed the quickfix list. Find the one we were 4408 /* Autocommands changed the quickfix list. Find the one we were
4489 4555
4490 #ifdef FEAT_AUTOCMD 4556 #ifdef FEAT_AUTOCMD
4491 if (au_name != NULL) 4557 if (au_name != NULL)
4492 apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, 4558 apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name,
4493 curbuf->b_fname, TRUE, curbuf); 4559 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;
4494 #endif 4567 #endif
4495 4568
4496 /* Jump to first match. */ 4569 /* Jump to first match. */
4497 if (qi->qf_lists[qi->qf_curlist].qf_count > 0) 4570 if (qi->qf_lists[qi->qf_curlist].qf_count > 0)
4498 { 4571 {
5541 # endif 5614 # endif
5542 } 5615 }
5543 #endif 5616 #endif
5544 5617
5545 /* Must come after autocommands. */ 5618 /* 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
5547 || eap->cmdidx == CMD_laddbuffer) 5621 || eap->cmdidx == CMD_laddbuffer)
5548 { 5622 {
5549 qi = ll_get_or_alloc_list(curwin); 5623 qi = ll_get_or_alloc_list(curwin);
5550 if (qi == NULL) 5624 if (qi == NULL)
5551 return; 5625 return;
5612 #ifdef FEAT_AUTOCMD 5686 #ifdef FEAT_AUTOCMD
5613 char_u *au_name = NULL; 5687 char_u *au_name = NULL;
5614 #endif 5688 #endif
5615 int res; 5689 int res;
5616 5690
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
5625 #ifdef FEAT_AUTOCMD 5691 #ifdef FEAT_AUTOCMD
5626 switch (eap->cmdidx) 5692 switch (eap->cmdidx)
5627 { 5693 {
5628 case CMD_cexpr: au_name = (char_u *)"cexpr"; break; 5694 case CMD_cexpr: au_name = (char_u *)"cexpr"; break;
5629 case CMD_cgetexpr: au_name = (char_u *)"cgetexpr"; break; 5695 case CMD_cgetexpr: au_name = (char_u *)"cgetexpr"; break;
5640 if (aborting()) 5706 if (aborting())
5641 return; 5707 return;
5642 # endif 5708 # endif
5643 } 5709 }
5644 #endif 5710 #endif
5711
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 }
5645 5720
5646 /* Evaluate the expression. When the result is a string or a list we can 5721 /* Evaluate the expression. When the result is a string or a list we can
5647 * use it to fill the errorlist. */ 5722 * use it to fill the errorlist. */
5648 tv = eval_expr(eap->arg, NULL); 5723 tv = eval_expr(eap->arg, NULL);
5649 if (tv != NULL) 5724 if (tv != NULL)