1
0
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:
Bram Moolenaar
2020-12-22 17:35:54 +01:00
parent 07761a3b96
commit cd45ed03bf
10 changed files with 148 additions and 96 deletions

View File

@@ -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);