comparison src/userfunc.c @ 31231:684e6dfa2fba v9.0.0949

patch 9.0.0949: crash when unletting a variable while listing variables Commit: https://github.com/vim/vim/commit/ef2c325f5e3c437b722bb96bf369ba2a5c541163 Author: Bram Moolenaar <Bram@vim.org> Date: Fri Nov 25 16:31:51 2022 +0000 patch 9.0.0949: crash when unletting a variable while listing variables Problem: Crash when unletting a variable while listing variables. Solution: Disallow changing a hashtable while going over the entries. (closes #11435)
author Bram Moolenaar <Bram@vim.org>
date Fri, 25 Nov 2022 17:45:04 +0100
parents c12069d28719
children 307f68a41b03
comparison
equal deleted inserted replaced
31230:e93800d75da2 31231:684e6dfa2fba
583 fp->uf_cb = cb; 583 fp->uf_cb = cb;
584 fp->uf_cb_free = cb_free; 584 fp->uf_cb_free = cb_free;
585 fp->uf_cb_state = state; 585 fp->uf_cb_state = state;
586 586
587 set_ufunc_name(fp, name); 587 set_ufunc_name(fp, name);
588 hash_add(&func_hashtab, UF2HIKEY(fp)); 588 hash_add(&func_hashtab, UF2HIKEY(fp), "add C function");
589 589
590 return name; 590 return name;
591 } 591 }
592 #endif 592 #endif
593 593
1276 name = get_lambda_name(); 1276 name = get_lambda_name();
1277 ufunc = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1); 1277 ufunc = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
1278 if (ufunc == NULL) 1278 if (ufunc == NULL)
1279 goto erret; 1279 goto erret;
1280 set_ufunc_name(ufunc, name); 1280 set_ufunc_name(ufunc, name);
1281 if (hash_add(&func_hashtab, UF2HIKEY(ufunc)) == FAIL) 1281 if (hash_add(&func_hashtab, UF2HIKEY(ufunc), "add function") == FAIL)
1282 goto erret; 1282 goto erret;
1283 ufunc->uf_flags = FC_LAMBDA; 1283 ufunc->uf_flags = FC_LAMBDA;
1284 ufunc->uf_refcount = 1; 1284 ufunc->uf_refcount = 1;
1285 ufunc->uf_args = *newargs; 1285 ufunc->uf_args = *newargs;
1286 newargs->ga_data = NULL; 1286 newargs->ga_data = NULL;
1570 pt->pt_func = fp; 1570 pt->pt_func = fp;
1571 pt->pt_refcount = 1; 1571 pt->pt_refcount = 1;
1572 rettv->vval.v_partial = pt; 1572 rettv->vval.v_partial = pt;
1573 rettv->v_type = VAR_PARTIAL; 1573 rettv->v_type = VAR_PARTIAL;
1574 1574
1575 hash_add(&func_hashtab, UF2HIKEY(fp)); 1575 hash_add(&func_hashtab, UF2HIKEY(fp), "add lambda");
1576 } 1576 }
1577 1577
1578 theend: 1578 theend:
1579 eval_lavars_used = old_eval_lavars; 1579 eval_lavars_used = old_eval_lavars;
1580 vim_free(tofree2); 1580 vim_free(tofree2);
2126 char *name, 2126 char *name,
2127 varnumber_T nr) 2127 varnumber_T nr)
2128 { 2128 {
2129 STRCPY(v->di_key, name); 2129 STRCPY(v->di_key, name);
2130 v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; 2130 v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
2131 hash_add(&dp->dv_hashtab, DI2HIKEY(v)); 2131 hash_add(&dp->dv_hashtab, DI2HIKEY(v), "add variable");
2132 v->di_tv.v_type = VAR_NUMBER; 2132 v->di_tv.v_type = VAR_NUMBER;
2133 v->di_tv.v_lock = VAR_FIXED; 2133 v->di_tv.v_lock = VAR_FIXED;
2134 v->di_tv.vval.v_number = nr; 2134 v->di_tv.vval.v_number = nr;
2135 } 2135 }
2136 2136
2346 if (fp->uf_def_status == UF_COMPILED && (fp->uf_flags & FC_COPY) == 0) 2346 if (fp->uf_def_status == UF_COMPILED && (fp->uf_flags & FC_COPY) == 0)
2347 { 2347 {
2348 fp->uf_flags |= FC_DEAD; 2348 fp->uf_flags |= FC_DEAD;
2349 return FALSE; 2349 return FALSE;
2350 } 2350 }
2351 hash_remove(&func_hashtab, hi); 2351 hash_remove(&func_hashtab, hi, "remove function");
2352 fp->uf_flags |= FC_DELETED; 2352 fp->uf_flags |= FC_DELETED;
2353 return TRUE; 2353 return TRUE;
2354 } 2354 }
2355 return FALSE; 2355 return FALSE;
2356 } 2356 }
2508 } 2508 }
2509 fp->uf_ret_type = ufunc->uf_ret_type; 2509 fp->uf_ret_type = ufunc->uf_ret_type;
2510 2510
2511 fp->uf_refcount = 1; 2511 fp->uf_refcount = 1;
2512 STRCPY(fp->uf_name, global); 2512 STRCPY(fp->uf_name, global);
2513 hash_add(&func_hashtab, UF2HIKEY(fp)); 2513 hash_add(&func_hashtab, UF2HIKEY(fp), "copy lambda");
2514 2514
2515 // the referenced dfunc_T is now used one more time 2515 // the referenced dfunc_T is now used one more time
2516 link_def_function(fp); 2516 link_def_function(fp);
2517 2517
2518 // Create a partial to store the context of the function where it was 2518 // Create a partial to store the context of the function where it was
2716 // some compiler that checks the destination size. 2716 // some compiler that checks the destination size.
2717 v = &fc->fc_fixvar[fixvar_idx++].var; 2717 v = &fc->fc_fixvar[fixvar_idx++].var;
2718 name = v->di_key; 2718 name = v->di_key;
2719 STRCPY(name, "self"); 2719 STRCPY(name, "self");
2720 v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; 2720 v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
2721 hash_add(&fc->fc_l_vars.dv_hashtab, DI2HIKEY(v)); 2721 hash_add(&fc->fc_l_vars.dv_hashtab, DI2HIKEY(v), "set self dictionary");
2722 v->di_tv.v_type = VAR_DICT; 2722 v->di_tv.v_type = VAR_DICT;
2723 v->di_tv.v_lock = 0; 2723 v->di_tv.v_lock = 0;
2724 v->di_tv.vval.v_dict = selfdict; 2724 v->di_tv.vval.v_dict = selfdict;
2725 ++selfdict->dv_refcount; 2725 ++selfdict->dv_refcount;
2726 } 2726 }
2742 // destination size. 2742 // destination size.
2743 v = &fc->fc_fixvar[fixvar_idx++].var; 2743 v = &fc->fc_fixvar[fixvar_idx++].var;
2744 name = v->di_key; 2744 name = v->di_key;
2745 STRCPY(name, "000"); 2745 STRCPY(name, "000");
2746 v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; 2746 v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
2747 hash_add(&fc->fc_l_avars.dv_hashtab, DI2HIKEY(v)); 2747 hash_add(&fc->fc_l_avars.dv_hashtab, DI2HIKEY(v), "function argument");
2748 v->di_tv.v_type = VAR_LIST; 2748 v->di_tv.v_type = VAR_LIST;
2749 v->di_tv.v_lock = VAR_FIXED; 2749 v->di_tv.v_lock = VAR_FIXED;
2750 v->di_tv.vval.v_list = &fc->fc_l_varlist; 2750 v->di_tv.vval.v_list = &fc->fc_l_varlist;
2751 } 2751 }
2752 CLEAR_FIELD(fc->fc_l_varlist); 2752 CLEAR_FIELD(fc->fc_l_varlist);
2836 if (addlocal) 2836 if (addlocal)
2837 { 2837 {
2838 // Named arguments should be accessed without the "a:" prefix in 2838 // Named arguments should be accessed without the "a:" prefix in
2839 // lambda expressions. Add to the l: dict. 2839 // lambda expressions. Add to the l: dict.
2840 copy_tv(&v->di_tv, &v->di_tv); 2840 copy_tv(&v->di_tv, &v->di_tv);
2841 hash_add(&fc->fc_l_vars.dv_hashtab, DI2HIKEY(v)); 2841 hash_add(&fc->fc_l_vars.dv_hashtab, DI2HIKEY(v), "local variable");
2842 } 2842 }
2843 else 2843 else
2844 hash_add(&fc->fc_l_avars.dv_hashtab, DI2HIKEY(v)); 2844 hash_add(&fc->fc_l_avars.dv_hashtab, DI2HIKEY(v), "add variable");
2845 2845
2846 if (ai >= 0 && ai < MAX_FUNC_ARGS) 2846 if (ai >= 0 && ai < MAX_FUNC_ARGS)
2847 { 2847 {
2848 listitem_T *li = &fc->fc_l_listitems[ai]; 2848 listitem_T *li = &fc->fc_l_listitems[ai];
2849 2849
5058 if (overwrite) 5058 if (overwrite)
5059 { 5059 {
5060 hi = hash_find(&func_hashtab, name); 5060 hi = hash_find(&func_hashtab, name);
5061 hi->hi_key = UF2HIKEY(fp); 5061 hi->hi_key = UF2HIKEY(fp);
5062 } 5062 }
5063 else if (hash_add(&func_hashtab, UF2HIKEY(fp)) == FAIL) 5063 else if (hash_add(&func_hashtab, UF2HIKEY(fp), "add function") == FAIL)
5064 { 5064 {
5065 free_fp = TRUE; 5065 free_fp = TRUE;
5066 goto erret; 5066 goto erret;
5067 } 5067 }
5068 fp->uf_refcount = 1; 5068 fp->uf_refcount = 1;
5460 5460
5461 if (fudi.fd_dict != NULL) 5461 if (fudi.fd_dict != NULL)
5462 { 5462 {
5463 // Delete the dict item that refers to the function, it will 5463 // Delete the dict item that refers to the function, it will
5464 // invoke func_unref() and possibly delete the function. 5464 // invoke func_unref() and possibly delete the function.
5465 dictitem_remove(fudi.fd_dict, fudi.fd_di); 5465 dictitem_remove(fudi.fd_dict, fudi.fd_di, "delfunction");
5466 } 5466 }
5467 else 5467 else
5468 { 5468 {
5469 // A normal function (not a numbered function or lambda) has a 5469 // A normal function (not a numbered function or lambda) has a
5470 // refcount of 1 for the entry in the hashtable. When deleting 5470 // refcount of 1 for the entry in the hashtable. When deleting