comparison src/userfunc.c @ 31081:c12069d28719 v9.0.0875

patch 9.0.0875: using freed memory when executing delfunc at more prompt Commit: https://github.com/vim/vim/commit/398a26f7fcd58fbc6e2329f892edbb7479a971bb Author: Bram Moolenaar <Bram@vim.org> Date: Sun Nov 13 22:13:33 2022 +0000 patch 9.0.0875: using freed memory when executing delfunc at more prompt Problem: Using freed memory when executing delfunc at the more prompt. Solution: Check function list not changed in another place. (closes https://github.com/vim/vim/issues/11437)
author Bram Moolenaar <Bram@vim.org>
date Sun, 13 Nov 2022 23:15:03 +0100
parents 360f286b5869
children 684e6dfa2fba
comparison
equal deleted inserted replaced
31080:df91dcf490f2 31081:c12069d28719
3791 { 3791 {
3792 return fp->uf_name_exp != NULL ? fp->uf_name_exp : fp->uf_name; 3792 return fp->uf_name_exp != NULL ? fp->uf_name_exp : fp->uf_name;
3793 } 3793 }
3794 3794
3795 /* 3795 /*
3796 * When "prev_ht_changed" does not equal "ht_changed" give an error and return
3797 * TRUE. Otherwise return FALSE.
3798 */
3799 static int
3800 function_list_modified(int prev_ht_changed)
3801 {
3802 if (prev_ht_changed != func_hashtab.ht_changed)
3803 {
3804 emsg(_(e_function_list_was_modified));
3805 return TRUE;
3806 }
3807 return FALSE;
3808 }
3809
3810 /*
3796 * List the head of the function: "function name(arg1, arg2)". 3811 * List the head of the function: "function name(arg1, arg2)".
3797 */ 3812 */
3798 static void 3813 static int
3799 list_func_head(ufunc_T *fp, int indent) 3814 list_func_head(ufunc_T *fp, int indent)
3800 { 3815 {
3816 int prev_ht_changed = func_hashtab.ht_changed;
3801 int j; 3817 int j;
3802 3818
3803 msg_start(); 3819 msg_start();
3820
3821 // a timer at the more prompt may have deleted the function
3822 if (function_list_modified(prev_ht_changed))
3823 return FAIL;
3824
3804 if (indent) 3825 if (indent)
3805 msg_puts(" "); 3826 msg_puts(" ");
3806 if (fp->uf_def_status != UF_NOT_COMPILED) 3827 if (fp->uf_def_status != UF_NOT_COMPILED)
3807 msg_puts("def "); 3828 msg_puts("def ");
3808 else 3829 else
3875 if (fp->uf_flags & FC_CLOSURE) 3896 if (fp->uf_flags & FC_CLOSURE)
3876 msg_puts(" closure"); 3897 msg_puts(" closure");
3877 msg_clr_eos(); 3898 msg_clr_eos();
3878 if (p_verbose > 0) 3899 if (p_verbose > 0)
3879 last_set_msg(fp->uf_script_ctx); 3900 last_set_msg(fp->uf_script_ctx);
3901
3902 return OK;
3880 } 3903 }
3881 3904
3882 /* 3905 /*
3883 * Get a function name, translating "<SID>" and "<SNR>". 3906 * Get a function name, translating "<SID>" and "<SNR>".
3884 * Also handles a Funcref in a List or Dictionary. 3907 * Also handles a Funcref in a List or Dictionary.
4313 * Otherwise functions matching "regmatch". 4336 * Otherwise functions matching "regmatch".
4314 */ 4337 */
4315 void 4338 void
4316 list_functions(regmatch_T *regmatch) 4339 list_functions(regmatch_T *regmatch)
4317 { 4340 {
4318 int changed = func_hashtab.ht_changed; 4341 int prev_ht_changed = func_hashtab.ht_changed;
4319 long_u todo = func_hashtab.ht_used; 4342 long_u todo = func_hashtab.ht_used;
4320 hashitem_T *hi; 4343 hashitem_T *hi;
4321 4344
4322 for (hi = func_hashtab.ht_array; todo > 0 && !got_int; ++hi) 4345 for (hi = func_hashtab.ht_array; todo > 0 && !got_int; ++hi)
4323 { 4346 {
4331 ? !message_filtered(fp->uf_name) 4354 ? !message_filtered(fp->uf_name)
4332 && !func_name_refcount(fp->uf_name) 4355 && !func_name_refcount(fp->uf_name)
4333 : !isdigit(*fp->uf_name) 4356 : !isdigit(*fp->uf_name)
4334 && vim_regexec(regmatch, fp->uf_name, 0))) 4357 && vim_regexec(regmatch, fp->uf_name, 0)))
4335 { 4358 {
4336 list_func_head(fp, FALSE); 4359 if (list_func_head(fp, FALSE) == FAIL)
4337 if (changed != func_hashtab.ht_changed)
4338 {
4339 emsg(_(e_function_list_was_modified));
4340 return; 4360 return;
4341 } 4361 if (function_list_modified(prev_ht_changed))
4362 return;
4342 } 4363 }
4343 } 4364 }
4344 } 4365 }
4345 } 4366 }
4346 4367
4540 fp = find_func(up, FALSE); 4561 fp = find_func(up, FALSE);
4541 } 4562 }
4542 4563
4543 if (fp != NULL) 4564 if (fp != NULL)
4544 { 4565 {
4545 list_func_head(fp, TRUE); 4566 // Check no function was added or removed from a timer, e.g. at
4546 for (j = 0; j < fp->uf_lines.ga_len && !got_int; ++j) 4567 // the more prompt. "fp" may then be invalid.
4568 int prev_ht_changed = func_hashtab.ht_changed;
4569
4570 if (list_func_head(fp, TRUE) == OK)
4547 { 4571 {
4548 if (FUNCLINE(fp, j) == NULL) 4572 for (j = 0; j < fp->uf_lines.ga_len && !got_int; ++j)
4549 continue; 4573 {
4550 msg_putchar('\n'); 4574 if (FUNCLINE(fp, j) == NULL)
4551 msg_outnum((long)(j + 1)); 4575 continue;
4552 if (j < 9) 4576 msg_putchar('\n');
4553 msg_putchar(' '); 4577 msg_outnum((long)(j + 1));
4554 if (j < 99) 4578 if (j < 9)
4555 msg_putchar(' '); 4579 msg_putchar(' ');
4556 msg_prt_line(FUNCLINE(fp, j), FALSE); 4580 if (j < 99)
4557 out_flush(); // show a line at a time 4581 msg_putchar(' ');
4558 ui_breakcheck(); 4582 if (function_list_modified(prev_ht_changed))
4559 } 4583 break;
4560 if (!got_int) 4584 msg_prt_line(FUNCLINE(fp, j), FALSE);
4561 { 4585 out_flush(); // show a line at a time
4562 msg_putchar('\n'); 4586 ui_breakcheck();
4563 if (fp->uf_def_status != UF_NOT_COMPILED) 4587 }
4564 msg_puts(" enddef"); 4588 if (!got_int)
4565 else 4589 {
4566 msg_puts(" endfunction"); 4590 msg_putchar('\n');
4591 if (!function_list_modified(prev_ht_changed))
4592 {
4593 if (fp->uf_def_status != UF_NOT_COMPILED)
4594 msg_puts(" enddef");
4595 else
4596 msg_puts(" endfunction");
4597 }
4598 }
4567 } 4599 }
4568 } 4600 }
4569 else 4601 else
4570 emsg_funcname(e_undefined_function_str, eap->arg); 4602 emsg_funcname(e_undefined_function_str, eap->arg);
4571 } 4603 }