Mercurial > vim
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 |