Mercurial > vim
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) |