mirror of
https://github.com/vim/vim.git
synced 2025-09-23 03:43:49 -04:00
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:
144
src/userfunc.c
144
src/userfunc.c
@@ -1260,8 +1260,7 @@ func_clear(ufunc_T *fp, int force)
|
||||
// clear this function
|
||||
func_clear_items(fp);
|
||||
funccal_unref(fp->uf_scoped, fp, force);
|
||||
if ((fp->uf_flags & FC_COPY) == 0)
|
||||
clear_def_function(fp);
|
||||
unlink_def_function(fp);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1307,75 +1306,98 @@ func_clear_free(ufunc_T *fp, int force)
|
||||
/*
|
||||
* Copy already defined function "lambda" to a new function with name "global".
|
||||
* This is for when a compiled function defines a global function.
|
||||
* Caller should take care of adding a partial for a closure.
|
||||
*/
|
||||
ufunc_T *
|
||||
copy_func(char_u *lambda, char_u *global)
|
||||
int
|
||||
copy_func(char_u *lambda, char_u *global, ectx_T *ectx)
|
||||
{
|
||||
ufunc_T *ufunc = find_func_even_dead(lambda, TRUE, NULL);
|
||||
ufunc_T *fp = NULL;
|
||||
|
||||
if (ufunc == NULL)
|
||||
semsg(_(e_lambda_function_not_found_str), lambda);
|
||||
else
|
||||
{
|
||||
// TODO: handle ! to overwrite
|
||||
fp = find_func(global, TRUE, NULL);
|
||||
if (fp != NULL)
|
||||
{
|
||||
semsg(_(e_funcexts), global);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fp = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(global) + 1);
|
||||
if (fp == NULL)
|
||||
return NULL;
|
||||
|
||||
fp->uf_varargs = ufunc->uf_varargs;
|
||||
fp->uf_flags = (ufunc->uf_flags & ~FC_VIM9) | FC_COPY;
|
||||
fp->uf_def_status = ufunc->uf_def_status;
|
||||
fp->uf_dfunc_idx = ufunc->uf_dfunc_idx;
|
||||
if (ga_copy_strings(&ufunc->uf_args, &fp->uf_args) == FAIL
|
||||
|| ga_copy_strings(&ufunc->uf_def_args, &fp->uf_def_args)
|
||||
== FAIL
|
||||
|| ga_copy_strings(&ufunc->uf_lines, &fp->uf_lines) == FAIL)
|
||||
goto failed;
|
||||
|
||||
fp->uf_name_exp = ufunc->uf_name_exp == NULL ? NULL
|
||||
: vim_strsave(ufunc->uf_name_exp);
|
||||
if (ufunc->uf_arg_types != NULL)
|
||||
{
|
||||
fp->uf_arg_types = ALLOC_MULT(type_T *, fp->uf_args.ga_len);
|
||||
if (fp->uf_arg_types == NULL)
|
||||
goto failed;
|
||||
mch_memmove(fp->uf_arg_types, ufunc->uf_arg_types,
|
||||
sizeof(type_T *) * fp->uf_args.ga_len);
|
||||
}
|
||||
if (ufunc->uf_def_arg_idx != NULL)
|
||||
{
|
||||
fp->uf_def_arg_idx = ALLOC_MULT(int, fp->uf_def_args.ga_len + 1);
|
||||
if (fp->uf_def_arg_idx == NULL)
|
||||
goto failed;
|
||||
mch_memmove(fp->uf_def_arg_idx, ufunc->uf_def_arg_idx,
|
||||
sizeof(int) * fp->uf_def_args.ga_len + 1);
|
||||
}
|
||||
if (ufunc->uf_va_name != NULL)
|
||||
{
|
||||
fp->uf_va_name = vim_strsave(ufunc->uf_va_name);
|
||||
if (fp->uf_va_name == NULL)
|
||||
goto failed;
|
||||
}
|
||||
fp->uf_ret_type = ufunc->uf_ret_type;
|
||||
|
||||
fp->uf_refcount = 1;
|
||||
STRCPY(fp->uf_name, global);
|
||||
hash_add(&func_hashtab, UF2HIKEY(fp));
|
||||
semsg(_(e_lambda_function_not_found_str), lambda);
|
||||
return FAIL;
|
||||
}
|
||||
return fp;
|
||||
|
||||
// TODO: handle ! to overwrite
|
||||
fp = find_func(global, TRUE, NULL);
|
||||
if (fp != NULL)
|
||||
{
|
||||
semsg(_(e_funcexts), global);
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
fp = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(global) + 1);
|
||||
if (fp == NULL)
|
||||
return FAIL;
|
||||
|
||||
fp->uf_varargs = ufunc->uf_varargs;
|
||||
fp->uf_flags = (ufunc->uf_flags & ~FC_VIM9) | FC_COPY;
|
||||
fp->uf_def_status = ufunc->uf_def_status;
|
||||
fp->uf_dfunc_idx = ufunc->uf_dfunc_idx;
|
||||
if (ga_copy_strings(&ufunc->uf_args, &fp->uf_args) == FAIL
|
||||
|| ga_copy_strings(&ufunc->uf_def_args, &fp->uf_def_args)
|
||||
== FAIL
|
||||
|| ga_copy_strings(&ufunc->uf_lines, &fp->uf_lines) == FAIL)
|
||||
goto failed;
|
||||
|
||||
fp->uf_name_exp = ufunc->uf_name_exp == NULL ? NULL
|
||||
: vim_strsave(ufunc->uf_name_exp);
|
||||
if (ufunc->uf_arg_types != NULL)
|
||||
{
|
||||
fp->uf_arg_types = ALLOC_MULT(type_T *, fp->uf_args.ga_len);
|
||||
if (fp->uf_arg_types == NULL)
|
||||
goto failed;
|
||||
mch_memmove(fp->uf_arg_types, ufunc->uf_arg_types,
|
||||
sizeof(type_T *) * fp->uf_args.ga_len);
|
||||
}
|
||||
if (ufunc->uf_def_arg_idx != NULL)
|
||||
{
|
||||
fp->uf_def_arg_idx = ALLOC_MULT(int, fp->uf_def_args.ga_len + 1);
|
||||
if (fp->uf_def_arg_idx == NULL)
|
||||
goto failed;
|
||||
mch_memmove(fp->uf_def_arg_idx, ufunc->uf_def_arg_idx,
|
||||
sizeof(int) * fp->uf_def_args.ga_len + 1);
|
||||
}
|
||||
if (ufunc->uf_va_name != NULL)
|
||||
{
|
||||
fp->uf_va_name = vim_strsave(ufunc->uf_va_name);
|
||||
if (fp->uf_va_name == NULL)
|
||||
goto failed;
|
||||
}
|
||||
fp->uf_ret_type = ufunc->uf_ret_type;
|
||||
|
||||
fp->uf_refcount = 1;
|
||||
STRCPY(fp->uf_name, global);
|
||||
hash_add(&func_hashtab, UF2HIKEY(fp));
|
||||
|
||||
// the referenced dfunc_T is now used one more time
|
||||
link_def_function(fp);
|
||||
|
||||
// Create a partial to store the context of the function, if not done
|
||||
// already.
|
||||
if ((ufunc->uf_flags & FC_CLOSURE) && ufunc->uf_partial == NULL)
|
||||
{
|
||||
partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
|
||||
|
||||
if (pt == NULL)
|
||||
goto failed;
|
||||
if (fill_partial_and_closure(pt, ufunc, ectx) == FAIL)
|
||||
goto failed;
|
||||
ufunc->uf_partial = pt;
|
||||
--pt->pt_refcount; // not referenced here yet
|
||||
}
|
||||
if (ufunc->uf_partial != NULL)
|
||||
{
|
||||
fp->uf_partial = ufunc->uf_partial;
|
||||
++fp->uf_partial->pt_refcount;
|
||||
}
|
||||
|
||||
return OK;
|
||||
|
||||
failed:
|
||||
func_clear_free(fp, TRUE);
|
||||
return NULL;
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
static int funcdepth = 0;
|
||||
@@ -3515,7 +3537,7 @@ define_function(exarg_T *eap, char_u *name_arg)
|
||||
fp->uf_profiling = FALSE;
|
||||
fp->uf_prof_initialized = FALSE;
|
||||
#endif
|
||||
clear_def_function(fp);
|
||||
unlink_def_function(fp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user