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)