Mercurial > vim
comparison src/arglist.c @ 23760:bb2afcad503b v8.2.2421
patch 8.2.2421: double free when using autocommand with "argdel"
Commit: https://github.com/vim/vim/commit/5ed58c7b700fcb9fd03c418300145b616f4bdcdd
Author: Bram Moolenaar <Bram@vim.org>
Date: Thu Jan 28 14:24:55 2021 +0100
patch 8.2.2421: double free when using autocommand with "argdel"
Problem: Double free when using autocommand with "argdel". (Houyunsong)
Solution: Add the arglist_locked flag.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Thu, 28 Jan 2021 14:30:05 +0100 |
parents | fc031340f8f9 |
children | 8b682f6f3709 |
comparison
equal
deleted
inserted
replaced
23759:63236203045e | 23760:bb2afcad503b |
---|---|
15 | 15 |
16 #define AL_SET 1 | 16 #define AL_SET 1 |
17 #define AL_ADD 2 | 17 #define AL_ADD 2 |
18 #define AL_DEL 3 | 18 #define AL_DEL 3 |
19 | 19 |
20 // This flag is set whenever the argument list is being changed and calling a | |
21 // function that might trigger an autocommand. | |
22 static int arglist_locked = FALSE; | |
23 | |
24 static int | |
25 check_arglist_locked(void) | |
26 { | |
27 if (arglist_locked) | |
28 { | |
29 emsg(_(e_cannot_change_arglist_recursively)); | |
30 return FAIL; | |
31 } | |
32 return OK; | |
33 } | |
34 | |
20 /* | 35 /* |
21 * Clear an argument list: free all file names and reset it to zero entries. | 36 * Clear an argument list: free all file names and reset it to zero entries. |
22 */ | 37 */ |
23 void | 38 void |
24 alist_clear(alist_T *al) | 39 alist_clear(alist_T *al) |
25 { | 40 { |
41 if (check_arglist_locked() == FAIL) | |
42 return; | |
26 while (--al->al_ga.ga_len >= 0) | 43 while (--al->al_ga.ga_len >= 0) |
27 vim_free(AARGLIST(al)[al->al_ga.ga_len].ae_fname); | 44 vim_free(AARGLIST(al)[al->al_ga.ga_len].ae_fname); |
28 ga_clear(&al->al_ga); | 45 ga_clear(&al->al_ga); |
29 } | 46 } |
30 | 47 |
124 int use_curbuf, | 141 int use_curbuf, |
125 int *fnum_list, | 142 int *fnum_list, |
126 int fnum_len) | 143 int fnum_len) |
127 { | 144 { |
128 int i; | 145 int i; |
129 static int recursive = 0; | 146 |
130 | 147 if (check_arglist_locked() == FAIL) |
131 if (recursive) | |
132 { | |
133 emsg(_(e_au_recursive)); | |
134 return; | 148 return; |
135 } | |
136 ++recursive; | |
137 | 149 |
138 alist_clear(al); | 150 alist_clear(al); |
139 if (ga_grow(&al->al_ga, count) == OK) | 151 if (ga_grow(&al->al_ga, count) == OK) |
140 { | 152 { |
141 for (i = 0; i < count; ++i) | 153 for (i = 0; i < count; ++i) |
150 } | 162 } |
151 | 163 |
152 // May set buffer name of a buffer previously used for the | 164 // May set buffer name of a buffer previously used for the |
153 // argument list, so that it's re-used by alist_add. | 165 // argument list, so that it's re-used by alist_add. |
154 if (fnum_list != NULL && i < fnum_len) | 166 if (fnum_list != NULL && i < fnum_len) |
167 { | |
168 arglist_locked = TRUE; | |
155 buf_set_name(fnum_list[i], files[i]); | 169 buf_set_name(fnum_list[i], files[i]); |
170 arglist_locked = FALSE; | |
171 } | |
156 | 172 |
157 alist_add(al, files[i], use_curbuf ? 2 : 1); | 173 alist_add(al, files[i], use_curbuf ? 2 : 1); |
158 ui_breakcheck(); | 174 ui_breakcheck(); |
159 } | 175 } |
160 vim_free(files); | 176 vim_free(files); |
161 } | 177 } |
162 else | 178 else |
163 FreeWild(count, files); | 179 FreeWild(count, files); |
164 if (al == &global_alist) | 180 if (al == &global_alist) |
165 arg_had_last = FALSE; | 181 arg_had_last = FALSE; |
166 | |
167 --recursive; | |
168 } | 182 } |
169 | 183 |
170 /* | 184 /* |
171 * Add file "fname" to argument list "al". | 185 * Add file "fname" to argument list "al". |
172 * "fname" must have been allocated and "al" must have been checked for room. | 186 * "fname" must have been allocated and "al" must have been checked for room. |
177 char_u *fname, | 191 char_u *fname, |
178 int set_fnum) // 1: set buffer number; 2: re-use curbuf | 192 int set_fnum) // 1: set buffer number; 2: re-use curbuf |
179 { | 193 { |
180 if (fname == NULL) // don't add NULL file names | 194 if (fname == NULL) // don't add NULL file names |
181 return; | 195 return; |
196 if (check_arglist_locked() == FAIL) | |
197 return; | |
198 arglist_locked = TRUE; | |
199 | |
182 #ifdef BACKSLASH_IN_FILENAME | 200 #ifdef BACKSLASH_IN_FILENAME |
183 slash_adjust(fname); | 201 slash_adjust(fname); |
184 #endif | 202 #endif |
185 AARGLIST(al)[al->al_ga.ga_len].ae_fname = fname; | 203 AARGLIST(al)[al->al_ga.ga_len].ae_fname = fname; |
186 if (set_fnum > 0) | 204 if (set_fnum > 0) |
187 AARGLIST(al)[al->al_ga.ga_len].ae_fnum = | 205 AARGLIST(al)[al->al_ga.ga_len].ae_fnum = |
188 buflist_add(fname, BLN_LISTED | (set_fnum == 2 ? BLN_CURBUF : 0)); | 206 buflist_add(fname, BLN_LISTED | (set_fnum == 2 ? BLN_CURBUF : 0)); |
189 ++al->al_ga.ga_len; | 207 ++al->al_ga.ga_len; |
208 | |
209 arglist_locked = FALSE; | |
190 } | 210 } |
191 | 211 |
192 #if defined(BACKSLASH_IN_FILENAME) || defined(PROTO) | 212 #if defined(BACKSLASH_IN_FILENAME) || defined(PROTO) |
193 /* | 213 /* |
194 * Adjust slashes in file names. Called after 'shellslash' was set. | 214 * Adjust slashes in file names. Called after 'shellslash' was set. |
332 int will_edit) // will edit adding argument | 352 int will_edit) // will edit adding argument |
333 { | 353 { |
334 int i; | 354 int i; |
335 int old_argcount = ARGCOUNT; | 355 int old_argcount = ARGCOUNT; |
336 | 356 |
337 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK) | 357 if (check_arglist_locked() != FAIL |
358 && ga_grow(&ALIST(curwin)->al_ga, count) == OK) | |
338 { | 359 { |
339 if (after < 0) | 360 if (after < 0) |
340 after = 0; | 361 after = 0; |
341 if (after > ARGCOUNT) | 362 if (after > ARGCOUNT) |
342 after = ARGCOUNT; | 363 after = ARGCOUNT; |
343 if (after < ARGCOUNT) | 364 if (after < ARGCOUNT) |
344 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]), | 365 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]), |
345 (ARGCOUNT - after) * sizeof(aentry_T)); | 366 (ARGCOUNT - after) * sizeof(aentry_T)); |
367 arglist_locked = TRUE; | |
346 for (i = 0; i < count; ++i) | 368 for (i = 0; i < count; ++i) |
347 { | 369 { |
348 int flags = BLN_LISTED | (will_edit ? BLN_CURBUF : 0); | 370 int flags = BLN_LISTED | (will_edit ? BLN_CURBUF : 0); |
349 | 371 |
350 ARGLIST[after + i].ae_fname = files[i]; | 372 ARGLIST[after + i].ae_fname = files[i]; |
351 ARGLIST[after + i].ae_fnum = buflist_add(files[i], flags); | 373 ARGLIST[after + i].ae_fnum = buflist_add(files[i], flags); |
352 } | 374 } |
375 arglist_locked = FALSE; | |
353 ALIST(curwin)->al_ga.ga_len += count; | 376 ALIST(curwin)->al_ga.ga_len += count; |
354 if (old_argcount > 0 && curwin->w_arg_idx >= after) | 377 if (old_argcount > 0 && curwin->w_arg_idx >= after) |
355 curwin->w_arg_idx += count; | 378 curwin->w_arg_idx += count; |
356 return; | 379 return; |
357 } | 380 } |
379 char_u **exp_files; | 402 char_u **exp_files; |
380 int i; | 403 int i; |
381 char_u *p; | 404 char_u *p; |
382 int match; | 405 int match; |
383 int arg_escaped = TRUE; | 406 int arg_escaped = TRUE; |
407 | |
408 if (check_arglist_locked() == FAIL) | |
409 return FAIL; | |
384 | 410 |
385 // Set default argument for ":argadd" command. | 411 // Set default argument for ":argadd" command. |
386 if (what == AL_ADD && *str == NUL) | 412 if (what == AL_ADD && *str == NUL) |
387 { | 413 { |
388 if (curbuf->b_ffname == NULL) | 414 if (curbuf->b_ffname == NULL) |
773 void | 799 void |
774 ex_argdelete(exarg_T *eap) | 800 ex_argdelete(exarg_T *eap) |
775 { | 801 { |
776 int i; | 802 int i; |
777 int n; | 803 int n; |
804 | |
805 if (check_arglist_locked() == FAIL) | |
806 return; | |
778 | 807 |
779 if (eap->addr_count > 0 || *eap->arg == NUL) | 808 if (eap->addr_count > 0 || *eap->arg == NUL) |
780 { | 809 { |
781 // ":argdel" works like ":.argdel" | 810 // ":argdel" works like ":.argdel" |
782 if (eap->addr_count == 0) | 811 if (eap->addr_count == 0) |