mirror of
https://github.com/vim/vim.git
synced 2025-09-23 03:43:49 -04:00
patch 9.0.0487: using freed memory with combination of closures
Problem: Using freed memory with combination of closures. Solution: Do not use a partial after it has been freed through the funcstack.
This commit is contained in:
@@ -4876,6 +4876,8 @@ partial_unref(partial_T *pt)
|
|||||||
{
|
{
|
||||||
if (pt != NULL)
|
if (pt != NULL)
|
||||||
{
|
{
|
||||||
|
int done = FALSE;
|
||||||
|
|
||||||
if (--pt->pt_refcount <= 0)
|
if (--pt->pt_refcount <= 0)
|
||||||
partial_free(pt);
|
partial_free(pt);
|
||||||
|
|
||||||
@@ -4883,9 +4885,12 @@ partial_unref(partial_T *pt)
|
|||||||
// only reference and can be freed if no other partials reference it.
|
// only reference and can be freed if no other partials reference it.
|
||||||
else if (pt->pt_refcount == 1)
|
else if (pt->pt_refcount == 1)
|
||||||
{
|
{
|
||||||
|
// careful: if the funcstack is freed it may contain this partial
|
||||||
|
// and it gets freed as well
|
||||||
if (pt->pt_funcstack != NULL)
|
if (pt->pt_funcstack != NULL)
|
||||||
funcstack_check_refcount(pt->pt_funcstack);
|
done = funcstack_check_refcount(pt->pt_funcstack);
|
||||||
if (pt->pt_loopvars != NULL)
|
|
||||||
|
if (!done && pt->pt_loopvars != NULL)
|
||||||
loopvars_check_refcount(pt->pt_loopvars);
|
loopvars_check_refcount(pt->pt_loopvars);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/* vim9execute.c */
|
/* vim9execute.c */
|
||||||
void to_string_error(vartype_T vartype);
|
void to_string_error(vartype_T vartype);
|
||||||
void update_has_breakpoint(ufunc_T *ufunc);
|
void update_has_breakpoint(ufunc_T *ufunc);
|
||||||
void funcstack_check_refcount(funcstack_T *funcstack);
|
int funcstack_check_refcount(funcstack_T *funcstack);
|
||||||
int set_ref_in_funcstacks(int copyID);
|
int set_ref_in_funcstacks(int copyID);
|
||||||
int in_def_function(void);
|
int in_def_function(void);
|
||||||
ectx_T *clear_currrent_ectx(void);
|
ectx_T *clear_currrent_ectx(void);
|
||||||
|
@@ -703,6 +703,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 */
|
||||||
|
/**/
|
||||||
|
487,
|
||||||
/**/
|
/**/
|
||||||
486,
|
486,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -797,16 +797,19 @@ handle_closure_in_use(ectx_T *ectx, int free_arguments)
|
|||||||
* funcstack may be the only reference to the partials in the local variables.
|
* funcstack may be the only reference to the partials in the local variables.
|
||||||
* Go over all of them, the funcref and can be freed if all partials
|
* Go over all of them, the funcref and can be freed if all partials
|
||||||
* referencing the funcstack have a reference count of one.
|
* referencing the funcstack have a reference count of one.
|
||||||
|
* Returns TRUE if the funcstack is freed, the partial referencing it will then
|
||||||
|
* also have been freed.
|
||||||
*/
|
*/
|
||||||
void
|
int
|
||||||
funcstack_check_refcount(funcstack_T *funcstack)
|
funcstack_check_refcount(funcstack_T *funcstack)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
garray_T *gap = &funcstack->fs_ga;
|
garray_T *gap = &funcstack->fs_ga;
|
||||||
int done = 0;
|
int done = 0;
|
||||||
|
typval_T *stack;
|
||||||
|
|
||||||
if (funcstack->fs_refcount > funcstack->fs_min_refcount)
|
if (funcstack->fs_refcount > funcstack->fs_min_refcount)
|
||||||
return;
|
return FALSE;
|
||||||
for (i = funcstack->fs_var_offset; i < gap->ga_len; ++i)
|
for (i = funcstack->fs_var_offset; i < gap->ga_len; ++i)
|
||||||
{
|
{
|
||||||
typval_T *tv = ((typval_T *)gap->ga_data) + i;
|
typval_T *tv = ((typval_T *)gap->ga_data) + i;
|
||||||
@@ -816,18 +819,20 @@ funcstack_check_refcount(funcstack_T *funcstack)
|
|||||||
&& tv->vval.v_partial->pt_refcount == 1)
|
&& tv->vval.v_partial->pt_refcount == 1)
|
||||||
++done;
|
++done;
|
||||||
}
|
}
|
||||||
if (done == funcstack->fs_min_refcount)
|
if (done != funcstack->fs_min_refcount)
|
||||||
{
|
return FALSE;
|
||||||
typval_T *stack = gap->ga_data;
|
|
||||||
|
|
||||||
// All partials referencing the funcstack have a reference count of
|
stack = gap->ga_data;
|
||||||
// one, thus the funcstack is no longer of use.
|
|
||||||
for (i = 0; i < gap->ga_len; ++i)
|
// All partials referencing the funcstack have a reference count of
|
||||||
clear_tv(stack + i);
|
// one, thus the funcstack is no longer of use.
|
||||||
vim_free(stack);
|
for (i = 0; i < gap->ga_len; ++i)
|
||||||
remove_funcstack_from_list(funcstack);
|
clear_tv(stack + i);
|
||||||
vim_free(funcstack);
|
vim_free(stack);
|
||||||
}
|
remove_funcstack_from_list(funcstack);
|
||||||
|
vim_free(funcstack);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Reference in New Issue
Block a user