Mercurial > vim
comparison src/insexpand.c @ 30487:79e2d9b7780c v9.0.0579
patch 9.0.0579: using freed memory when 'tagfunc' wipes out buffer
Commit: https://github.com/vim/vim/commit/0ff01835a40f549c5c4a550502f62a2ac9ac447c
Author: Bram Moolenaar <Bram@vim.org>
Date: Sat Sep 24 19:20:30 2022 +0100
patch 9.0.0579: using freed memory when 'tagfunc' wipes out buffer
Problem: Using freed memory when 'tagfunc' wipes out buffer that holds
'complete'.
Solution: Make a copy of the option. Make sure cursor position is valid.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sat, 24 Sep 2022 20:30:03 +0200 |
parents | faecc8c6916f |
children | 101f08b49ed3 |
comparison
equal
deleted
inserted
replaced
30486:004697058faf | 30487:79e2d9b7780c |
---|---|
2488 { | 2488 { |
2489 static win_T *wp = NULL; | 2489 static win_T *wp = NULL; |
2490 | 2490 |
2491 if (flag == 'w') // just windows | 2491 if (flag == 'w') // just windows |
2492 { | 2492 { |
2493 if (buf == curbuf || wp == NULL) // first call for this flag/expansion | 2493 if (buf == curbuf || !win_valid(wp)) |
2494 // first call for this flag/expansion or window was closed | |
2494 wp = curwin; | 2495 wp = curwin; |
2495 while ((wp = (wp->w_next != NULL ? wp->w_next : firstwin)) != curwin | 2496 while ((wp = (wp->w_next != NULL ? wp->w_next : firstwin)) != curwin |
2496 && wp->w_buffer->b_scanned) | 2497 && wp->w_buffer->b_scanned) |
2497 ; | 2498 ; |
2498 buf = wp->w_buffer; | 2499 buf = wp->w_buffer; |
3186 * state information used for getting the next set of insert completion | 3187 * state information used for getting the next set of insert completion |
3187 * matches. | 3188 * matches. |
3188 */ | 3189 */ |
3189 typedef struct | 3190 typedef struct |
3190 { | 3191 { |
3191 char_u *e_cpt; // current entry in 'complete' | 3192 char_u *e_cpt_copy; // copy of 'complete' |
3193 char_u *e_cpt; // current entry in "e_cpt_copy" | |
3192 buf_T *ins_buf; // buffer being scanned | 3194 buf_T *ins_buf; // buffer being scanned |
3193 pos_T *cur_match_pos; // current match position | 3195 pos_T *cur_match_pos; // current match position |
3194 pos_T prev_match_pos; // previous match position | 3196 pos_T prev_match_pos; // previous match position |
3195 int set_match_pos; // save first_match_pos/last_match_pos | 3197 int set_match_pos; // save first_match_pos/last_match_pos |
3196 pos_T first_match_pos; // first match position | 3198 pos_T first_match_pos; // first match position |
3197 pos_T last_match_pos; // last match position | 3199 pos_T last_match_pos; // last match position |
3198 int found_all; // found all matches of a certain type. | 3200 int found_all; // found all matches of a certain type. |
3255 // Remember the first match so that the loop stops when we | 3257 // Remember the first match so that the loop stops when we |
3256 // wrap and come back there a second time. | 3258 // wrap and come back there a second time. |
3257 st->set_match_pos = TRUE; | 3259 st->set_match_pos = TRUE; |
3258 } | 3260 } |
3259 else if (vim_strchr((char_u *)"buwU", *st->e_cpt) != NULL | 3261 else if (vim_strchr((char_u *)"buwU", *st->e_cpt) != NULL |
3260 && (st->ins_buf = ins_compl_next_buf(st->ins_buf, *st->e_cpt)) != curbuf) | 3262 && (st->ins_buf = ins_compl_next_buf( |
3263 st->ins_buf, *st->e_cpt)) != curbuf) | |
3261 { | 3264 { |
3262 // Scan a buffer, but not the current one. | 3265 // Scan a buffer, but not the current one. |
3263 if (st->ins_buf->b_ml.ml_mfp != NULL) // loaded buffer | 3266 if (st->ins_buf->b_ml.ml_mfp != NULL) // loaded buffer |
3264 { | 3267 { |
3265 compl_started = TRUE; | 3268 compl_started = TRUE; |
3754 * Return the total number of matches or -1 if still unknown -- Acevedo | 3757 * Return the total number of matches or -1 if still unknown -- Acevedo |
3755 */ | 3758 */ |
3756 static int | 3759 static int |
3757 ins_compl_get_exp(pos_T *ini) | 3760 ins_compl_get_exp(pos_T *ini) |
3758 { | 3761 { |
3759 static ins_compl_next_state_T st; | 3762 static ins_compl_next_state_T st; |
3763 static int st_cleared = FALSE; | |
3760 int i; | 3764 int i; |
3761 int found_new_match; | 3765 int found_new_match; |
3762 int type = ctrl_x_mode; | 3766 int type = ctrl_x_mode; |
3763 | 3767 |
3764 if (!compl_started) | 3768 if (!compl_started) |
3765 { | 3769 { |
3766 FOR_ALL_BUFFERS(st.ins_buf) | 3770 buf_T *buf; |
3767 st.ins_buf->b_scanned = 0; | 3771 |
3772 FOR_ALL_BUFFERS(buf) | |
3773 buf->b_scanned = 0; | |
3774 if (!st_cleared) | |
3775 { | |
3776 CLEAR_FIELD(st); | |
3777 st_cleared = TRUE; | |
3778 } | |
3768 st.found_all = FALSE; | 3779 st.found_all = FALSE; |
3769 st.ins_buf = curbuf; | 3780 st.ins_buf = curbuf; |
3770 st.e_cpt = (compl_cont_status & CONT_LOCAL) | 3781 vim_free(st.e_cpt_copy); |
3771 ? (char_u *)"." : curbuf->b_p_cpt; | 3782 // Make a copy of 'complete', if case the buffer is wiped out. |
3783 st.e_cpt_copy = vim_strsave((compl_cont_status & CONT_LOCAL) | |
3784 ? (char_u *)"." : curbuf->b_p_cpt); | |
3785 st.e_cpt = st.e_cpt_copy == NULL ? (char_u *)"" : st.e_cpt_copy; | |
3772 st.last_match_pos = st.first_match_pos = *ini; | 3786 st.last_match_pos = st.first_match_pos = *ini; |
3773 } | 3787 } |
3774 else if (st.ins_buf != curbuf && !buf_valid(st.ins_buf)) | 3788 else if (st.ins_buf != curbuf && !buf_valid(st.ins_buf)) |
3775 st.ins_buf = curbuf; // In case the buffer was wiped out. | 3789 st.ins_buf = curbuf; // In case the buffer was wiped out. |
3776 | 3790 |
4110 { | 4124 { |
4111 int num_matches = -1; | 4125 int num_matches = -1; |
4112 int todo = count; | 4126 int todo = count; |
4113 int advance; | 4127 int advance; |
4114 int started = compl_started; | 4128 int started = compl_started; |
4129 buf_T *orig_curbuf = curbuf; | |
4115 | 4130 |
4116 // When user complete function return -1 for findstart which is next | 4131 // When user complete function return -1 for findstart which is next |
4117 // time of 'always', compl_shown_match become NULL. | 4132 // time of 'always', compl_shown_match become NULL. |
4118 if (compl_shown_match == NULL) | 4133 if (compl_shown_match == NULL) |
4119 return -1; | 4134 return -1; |
4141 // Repeat this for when <PageUp> or <PageDown> is typed. But don't wrap | 4156 // Repeat this for when <PageUp> or <PageDown> is typed. But don't wrap |
4142 // around. | 4157 // around. |
4143 if (find_next_completion_match(allow_get_expansion, todo, advance, | 4158 if (find_next_completion_match(allow_get_expansion, todo, advance, |
4144 &num_matches) == -1) | 4159 &num_matches) == -1) |
4145 return -1; | 4160 return -1; |
4161 | |
4162 if (curbuf != orig_curbuf) | |
4163 { | |
4164 // In case some completion function switched buffer, don't want to | |
4165 // insert the completion elsewhere. | |
4166 return -1; | |
4167 } | |
4146 | 4168 |
4147 // Insert the text of the new completion, or the compl_leader. | 4169 // Insert the text of the new completion, or the compl_leader. |
4148 if (compl_no_insert && !started) | 4170 if (compl_no_insert && !started) |
4149 { | 4171 { |
4150 ins_bytes(compl_orig_text + get_compl_len()); | 4172 ins_bytes(compl_orig_text + get_compl_len()); |