0
0
mirror of https://github.com/vim/vim.git synced 2025-09-25 03:54:15 -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:
Bram Moolenaar
2021-12-10 10:37:38 +00:00
parent dee78e1ce8
commit dd297bc11d
5 changed files with 49 additions and 3 deletions

View File

@@ -3291,6 +3291,7 @@ set_var_const(
int vim9script = in_vim9script(); int vim9script = in_vim9script();
int var_in_vim9script; int var_in_vim9script;
int flags = flags_arg; int flags = flags_arg;
int free_tv_arg = !copy; // free tv_arg if not used
ht = find_var_ht(name, &varname); ht = find_var_ht(name, &varname);
if (ht == NULL || *varname == NUL) if (ht == NULL || *varname == NUL)
@@ -3545,6 +3546,7 @@ set_var_const(
dest_tv->v_lock = 0; dest_tv->v_lock = 0;
init_tv(tv); init_tv(tv);
} }
free_tv_arg = FALSE;
if (vim9script && type != NULL) if (vim9script && type != NULL)
{ {
@@ -3573,10 +3575,9 @@ set_var_const(
// if the reference count is up to one. That locks only literal // if the reference count is up to one. That locks only literal
// values. // values.
item_lock(dest_tv, DICT_MAXNEST, TRUE, TRUE); item_lock(dest_tv, DICT_MAXNEST, TRUE, TRUE);
return;
failed: failed:
if (!copy) if (free_tv_arg)
clear_tv(tv_arg); clear_tv(tv_arg);
} }

View File

@@ -1809,6 +1809,7 @@ struct svar_S {
char_u *sv_name; // points into "sn_all_vars" di_key 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 typval_T *sv_tv; // points into "sn_vars" or "sn_all_vars" di_tv
type_T *sv_type; 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_const; // 0, ASSIGN_CONST or ASSIGN_FINAL
int sv_export; // "export let var = val" int sv_export; // "export let var = val"
}; };

View File

@@ -1224,6 +1224,25 @@ def Test_set_opfunc_to_lambda()
CheckScriptSuccess(lines) CheckScriptSuccess(lines)
enddef 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 " Default arg and varargs
def MyDefVarargs(one: string, two = 'foo', ...rest: list<string>): string def MyDefVarargs(one: string, two = 'foo', ...rest: list<string>): string
var res = one .. ',' .. two var res = one .. ',' .. two

View File

@@ -753,6 +753,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
3771,
/**/ /**/
3770, 3770,
/**/ /**/

View File

@@ -268,6 +268,7 @@ free_all_script_vars(scriptitem_T *si)
hashitem_T *hi; hashitem_T *hi;
sallvar_T *sav; sallvar_T *sav;
sallvar_T *sav_next; sallvar_T *sav_next;
int idx;
hash_lock(ht); hash_lock(ht);
todo = (int)ht->ht_used; todo = (int)ht->ht_used;
@@ -293,6 +294,13 @@ free_all_script_vars(scriptitem_T *si)
hash_clear(ht); hash_clear(ht);
hash_init(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); ga_clear(&si->sn_var_vals);
// existing commands using script variable indexes are no longer valid // existing commands using script variable indexes are no longer valid
@@ -899,7 +907,22 @@ update_vim9_script_var(
{ {
if (*type == NULL) if (*type == NULL)
*type = typval2type(tv, get_copyID(), &si->sn_type_list, do_member); *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. // let ex_export() know the export worked.