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:
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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"
|
||||||
};
|
};
|
||||||
|
@@ -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
|
||||||
|
@@ -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,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -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.
|
||||||
|
Reference in New Issue
Block a user