diff options
author | Bram Moolenaar <Bram@vim.org> | 2022-11-25 16:31:51 +0000 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2022-11-25 16:31:51 +0000 |
commit | ef2c325f5e3c437b722bb96bf369ba2a5c541163 (patch) | |
tree | dc85f0dc98dce1937b459d8d3882473f25db03c3 /src/evalvars.c | |
parent | c1cf4c91072f91b6b8dd636627a4ddf6f4b21f16 (diff) |
patch 9.0.0949: crash when unletting a variable while listing variablesv9.0.0949
Problem: Crash when unletting a variable while listing variables.
Solution: Disallow changing a hashtable while going over the entries.
(closes #11435)
Diffstat (limited to 'src/evalvars.c')
-rw-r--r-- | src/evalvars.c | 31 |
1 files changed, 21 insertions, 10 deletions
diff --git a/src/evalvars.c b/src/evalvars.c index 793f5632c2..28516c172b 100644 --- a/src/evalvars.c +++ b/src/evalvars.c @@ -217,10 +217,10 @@ evalvars_init(void) // add to v: scope dict, unless the value is not always available if (p->vv_tv_type != VAR_UNKNOWN) - hash_add(&vimvarht, p->vv_di.di_key); + hash_add(&vimvarht, p->vv_di.di_key, "initialization"); if (p->vv_flags & VV_COMPAT) // add to compat scope dict - hash_add(&compat_hashtab, p->vv_di.di_key); + hash_add(&compat_hashtab, p->vv_di.di_key, "initialization"); } set_vim_var_nr(VV_VERSION, VIM_VERSION_100); set_vim_var_nr(VV_VERSIONLONG, VIM_VERSION_100 * 10000 + highest_patch()); @@ -562,7 +562,7 @@ prepare_vimvar(int idx, typval_T *save_tv) *save_tv = vimvars[idx].vv_tv; vimvars[idx].vv_str = NULL; // don't free it now if (vimvars[idx].vv_tv_type == VAR_UNKNOWN) - hash_add(&vimvarht, vimvars[idx].vv_di.di_key); + hash_add(&vimvarht, vimvars[idx].vv_di.di_key, "prepare vimvar"); } /* @@ -582,7 +582,7 @@ restore_vimvar(int idx, typval_T *save_tv) if (HASHITEM_EMPTY(hi)) internal_error("restore_vimvar()"); else - hash_remove(&vimvarht, hi); + hash_remove(&vimvarht, hi, "restore vimvar"); } } @@ -1380,6 +1380,9 @@ list_hashtable_vars( int todo; char_u buf[IOSIZE]; + int save_ht_flags = ht->ht_flags; + ht->ht_flags |= HTFLAGS_FROZEN; + todo = (int)ht->ht_used; for (hi = ht->ht_array; todo > 0 && !got_int; ++hi) { @@ -1399,6 +1402,8 @@ list_hashtable_vars( list_one_var(di, prefix, first); } } + + ht->ht_flags = save_ht_flags; } /* @@ -2008,7 +2013,7 @@ do_unlet_var( listitem_remove(lp->ll_list, lp->ll_li); else // unlet a Dictionary item. - dictitem_remove(lp->ll_dict, lp->ll_di); + dictitem_remove(lp->ll_dict, lp->ll_di, "unlet"); return ret; } @@ -2095,7 +2100,8 @@ do_unlet(char_u *name, int forceit) di = HI2DI(hi); if (var_check_fixed(di->di_flags, name, FALSE) || var_check_ro(di->di_flags, name, FALSE) - || value_check_lock(d->dv_lock, name, FALSE)) + || value_check_lock(d->dv_lock, name, FALSE) + || check_hashtab_frozen(ht, "unlet")) return FAIL; delete_var(ht, hi); @@ -3554,9 +3560,11 @@ delete_var(hashtab_T *ht, hashitem_T *hi) { dictitem_T *di = HI2DI(hi); - hash_remove(ht, hi); - clear_tv(&di->di_tv); - vim_free(di); + if (hash_remove(ht, hi, "delete variable") == OK) + { + clear_tv(&di->di_tv); + vim_free(di); + } } /* @@ -3895,6 +3903,9 @@ set_var_const( goto failed; } + if (check_hashtab_frozen(ht, "add variable")) + goto failed; + // Can't add "v:" or "a:" variable. if (ht == &vimvarht || ht == get_funccal_args_ht()) { @@ -3913,7 +3924,7 @@ set_var_const( if (di == NULL) goto failed; STRCPY(di->di_key, varname); - if (hash_add(ht, DI2HIKEY(di)) == FAIL) + if (hash_add(ht, DI2HIKEY(di), "add variable") == FAIL) { vim_free(di); goto failed; |