mirror of
https://github.com/vim/vim.git
synced 2025-09-24 03:44:06 -04:00
patch 8.2.3771: Vim9: accessing freed memory when checking type
Problem: Vim9: accessing freed memory when checking type. Solution: Make a copy of a function type.
This commit is contained in:
@@ -3291,6 +3291,7 @@ set_var_const(
|
||||
int vim9script = in_vim9script();
|
||||
int var_in_vim9script;
|
||||
int flags = flags_arg;
|
||||
int free_tv_arg = !copy; // free tv_arg if not used
|
||||
|
||||
ht = find_var_ht(name, &varname);
|
||||
if (ht == NULL || *varname == NUL)
|
||||
@@ -3545,6 +3546,7 @@ set_var_const(
|
||||
dest_tv->v_lock = 0;
|
||||
init_tv(tv);
|
||||
}
|
||||
free_tv_arg = FALSE;
|
||||
|
||||
if (vim9script && type != NULL)
|
||||
{
|
||||
@@ -3573,10 +3575,9 @@ set_var_const(
|
||||
// if the reference count is up to one. That locks only literal
|
||||
// values.
|
||||
item_lock(dest_tv, DICT_MAXNEST, TRUE, TRUE);
|
||||
return;
|
||||
|
||||
failed:
|
||||
if (!copy)
|
||||
if (free_tv_arg)
|
||||
clear_tv(tv_arg);
|
||||
}
|
||||
|
||||
|
@@ -1809,6 +1809,7 @@ struct svar_S {
|
||||
char_u *sv_name; // points into "sn_all_vars" di_key
|
||||
typval_T *sv_tv; // points into "sn_vars" or "sn_all_vars" di_tv
|
||||
type_T *sv_type;
|
||||
int sv_type_allocated; // call free_type() for sv_type
|
||||
int sv_const; // 0, ASSIGN_CONST or ASSIGN_FINAL
|
||||
int sv_export; // "export let var = val"
|
||||
};
|
||||
|
@@ -1224,6 +1224,25 @@ def Test_set_opfunc_to_lambda()
|
||||
CheckScriptSuccess(lines)
|
||||
enddef
|
||||
|
||||
def Test_lambda_type_allocated()
|
||||
# Check that unreferencing a partial using a lambda can use the variable type
|
||||
# after the lambda has been freed and does not leak memory.
|
||||
var lines =<< trim END
|
||||
vim9script
|
||||
|
||||
func MyomniFunc1(val, findstart, base)
|
||||
return a:findstart ? 0 : []
|
||||
endfunc
|
||||
|
||||
var Lambda = (a, b) => MyomniFunc1(19, a, b)
|
||||
&omnifunc = Lambda
|
||||
Lambda = (a, b) => MyomniFunc1(20, a, b)
|
||||
&omnifunc = string(Lambda)
|
||||
Lambda = (a, b) => strlen(a)
|
||||
END
|
||||
CheckScriptSuccess(lines)
|
||||
enddef
|
||||
|
||||
" Default arg and varargs
|
||||
def MyDefVarargs(one: string, two = 'foo', ...rest: list<string>): string
|
||||
var res = one .. ',' .. two
|
||||
|
@@ -753,6 +753,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
3771,
|
||||
/**/
|
||||
3770,
|
||||
/**/
|
||||
|
@@ -268,6 +268,7 @@ free_all_script_vars(scriptitem_T *si)
|
||||
hashitem_T *hi;
|
||||
sallvar_T *sav;
|
||||
sallvar_T *sav_next;
|
||||
int idx;
|
||||
|
||||
hash_lock(ht);
|
||||
todo = (int)ht->ht_used;
|
||||
@@ -293,6 +294,13 @@ free_all_script_vars(scriptitem_T *si)
|
||||
hash_clear(ht);
|
||||
hash_init(ht);
|
||||
|
||||
for (idx = 0; idx < si->sn_var_vals.ga_len; ++idx)
|
||||
{
|
||||
svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data) + idx;
|
||||
|
||||
if (sv->sv_type_allocated)
|
||||
free_type(sv->sv_type);
|
||||
}
|
||||
ga_clear(&si->sn_var_vals);
|
||||
|
||||
// existing commands using script variable indexes are no longer valid
|
||||
@@ -899,7 +907,22 @@ update_vim9_script_var(
|
||||
{
|
||||
if (*type == NULL)
|
||||
*type = typval2type(tv, get_copyID(), &si->sn_type_list, do_member);
|
||||
sv->sv_type = *type;
|
||||
if (sv->sv_type_allocated)
|
||||
free_type(sv->sv_type);
|
||||
if (*type != NULL && ((*type)->tt_type == VAR_FUNC
|
||||
|| (*type)->tt_type == VAR_PARTIAL))
|
||||
{
|
||||
// The type probably uses uf_type_list, which is cleared when the
|
||||
// function is freed, but the script variable may keep the type.
|
||||
// Make a copy to avoid using freed memory.
|
||||
sv->sv_type = alloc_type(*type);
|
||||
sv->sv_type_allocated = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
sv->sv_type = *type;
|
||||
sv->sv_type_allocated = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// let ex_export() know the export worked.
|
||||
|
Reference in New Issue
Block a user