forked from aniani/vim
patch 8.2.2188: Vim9: crash when calling global function from :def function
Problem: Vim9: crash when calling global function from :def function. Solution: Set the outer context. Define the partial for the context on the original function. Use a refcount to keep track of which ufunc is using a dfunc. (closes #7525)
This commit is contained in:
@@ -7336,6 +7336,8 @@ add_def_function(ufunc_T *ufunc)
|
||||
dfunc->df_idx = def_functions.ga_len;
|
||||
ufunc->uf_dfunc_idx = dfunc->df_idx;
|
||||
dfunc->df_ufunc = ufunc;
|
||||
dfunc->df_name = vim_strsave(ufunc->uf_name);
|
||||
++dfunc->df_refcount;
|
||||
++def_functions.ga_len;
|
||||
return OK;
|
||||
}
|
||||
@@ -7928,6 +7930,7 @@ erret:
|
||||
for (idx = 0; idx < instr->ga_len; ++idx)
|
||||
delete_instr(((isn_T *)instr->ga_data) + idx);
|
||||
ga_clear(instr);
|
||||
VIM_CLEAR(dfunc->df_name);
|
||||
|
||||
// If using the last entry in the table and it was added above, we
|
||||
// might as well remove it.
|
||||
@@ -8102,9 +8105,7 @@ delete_instr(isn_T *isn)
|
||||
|
||||
if (ufunc != NULL)
|
||||
{
|
||||
// Clear uf_dfunc_idx so that the function is deleted.
|
||||
clear_def_function(ufunc);
|
||||
ufunc->uf_dfunc_idx = 0;
|
||||
unlink_def_function(ufunc);
|
||||
func_ptr_unref(ufunc);
|
||||
}
|
||||
|
||||
@@ -8206,7 +8207,7 @@ delete_instr(isn_T *isn)
|
||||
}
|
||||
|
||||
/*
|
||||
* Free all instructions for "dfunc".
|
||||
* Free all instructions for "dfunc" except df_name.
|
||||
*/
|
||||
static void
|
||||
delete_def_function_contents(dfunc_T *dfunc)
|
||||
@@ -8227,31 +8228,39 @@ delete_def_function_contents(dfunc_T *dfunc)
|
||||
|
||||
/*
|
||||
* When a user function is deleted, clear the contents of any associated def
|
||||
* function. The position in def_functions can be re-used.
|
||||
* function, unless another user function still uses it.
|
||||
* The position in def_functions can be re-used.
|
||||
*/
|
||||
void
|
||||
clear_def_function(ufunc_T *ufunc)
|
||||
unlink_def_function(ufunc_T *ufunc)
|
||||
{
|
||||
if (ufunc->uf_dfunc_idx > 0)
|
||||
{
|
||||
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
|
||||
+ ufunc->uf_dfunc_idx;
|
||||
|
||||
delete_def_function_contents(dfunc);
|
||||
if (--dfunc->df_refcount <= 0)
|
||||
delete_def_function_contents(dfunc);
|
||||
ufunc->uf_def_status = UF_NOT_COMPILED;
|
||||
ufunc->uf_dfunc_idx = 0;
|
||||
if (dfunc->df_ufunc == ufunc)
|
||||
dfunc->df_ufunc = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Used when a user function is about to be deleted: remove the pointer to it.
|
||||
* The entry in def_functions is then unused.
|
||||
* Used when a user function refers to an existing dfunc.
|
||||
*/
|
||||
void
|
||||
unlink_def_function(ufunc_T *ufunc)
|
||||
link_def_function(ufunc_T *ufunc)
|
||||
{
|
||||
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx;
|
||||
if (ufunc->uf_dfunc_idx > 0)
|
||||
{
|
||||
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
|
||||
+ ufunc->uf_dfunc_idx;
|
||||
|
||||
dfunc->df_ufunc = NULL;
|
||||
++dfunc->df_refcount;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(EXITFREE) || defined(PROTO)
|
||||
@@ -8268,6 +8277,7 @@ free_def_functions(void)
|
||||
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + idx;
|
||||
|
||||
delete_def_function_contents(dfunc);
|
||||
vim_free(dfunc->df_name);
|
||||
}
|
||||
|
||||
ga_clear(&def_functions);
|
||||
|
Reference in New Issue
Block a user