1
0
forked from aniani/vim

patch 8.2.2614: Vim9: function is deleted while executing

Problem:    Vim9: function is deleted while executing.
Solution:   increment the call count, when more than zero do not delete the
            function but mark it as dead. (closes #7977)
This commit is contained in:
Bram Moolenaar
2021-03-17 15:03:04 +01:00
parent 6ccfd99b92
commit c970e4225b
4 changed files with 65 additions and 9 deletions

View File

@@ -1561,6 +1561,35 @@ def Test_script_reload_change_type()
delete('Xreload.vim')
enddef
" Define CallFunc so that the test can be compiled
command CallFunc echo 'nop'
def Test_script_reload_from_function()
var lines =<< trim END
vim9script
if exists('g:loaded')
finish
endif
g:loaded = 1
delcommand CallFunc
command CallFunc Func()
def Func()
so /tmp/test.vim
g:didTheFunc = 1
enddef
END
writefile(lines, 'XreloadFunc.vim')
source XreloadFunc.vim
CallFunc
assert_equal(1, g:didTheFunc)
delete('XreloadFunc.vim')
delcommand CallFunc
unlet g:loaded
unlet g:didTheFunc
enddef
def Test_script_var_shadows_function()
var lines =<< trim END
vim9script

View File

@@ -1359,9 +1359,12 @@ func_remove(ufunc_T *fp)
// function, so we can find the index when defining the function again.
// Do remove it when it's a copy.
if (fp->uf_def_status == UF_COMPILED && (fp->uf_flags & FC_COPY) == 0)
{
fp->uf_flags |= FC_DEAD;
else
hash_remove(&func_hashtab, hi);
return FALSE;
}
hash_remove(&func_hashtab, hi);
fp->uf_flags |= FC_DELETED;
return TRUE;
}
return FALSE;
@@ -2134,11 +2137,23 @@ delete_script_functions(int sid)
int changed = func_hashtab.ht_changed;
fp->uf_flags |= FC_DEAD;
func_clear(fp, TRUE);
// When clearing a function another function can be cleared
// as a side effect. When that happens start over.
if (changed != func_hashtab.ht_changed)
break;
if (fp->uf_calls > 0)
{
// Function is executing, don't free it but do remove
// it from the hashtable.
if (func_remove(fp))
fp->uf_refcount--;
}
else
{
func_clear(fp, TRUE);
// When clearing a function another function can be
// cleared as a side effect. When that happens start
// over.
if (changed != func_hashtab.ht_changed)
break;
}
}
--todo;
}
@@ -4251,7 +4266,6 @@ ex_delfunction(exarg_T *eap)
// do remove it from the hashtable.
if (func_remove(fp))
fp->uf_refcount--;
fp->uf_flags |= FC_DELETED;
}
else
func_clear_free(fp, FALSE);

View File

@@ -750,6 +750,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
2614,
/**/
2613,
/**/

View File

@@ -323,6 +323,8 @@ call_dfunc(int cdf_idx, partial_T *pt, int argcount_arg, ectx_T *ectx)
else
ectx->ec_outer = NULL;
++ufunc->uf_calls;
// Set execution state to the start of the called function.
ectx->ec_dfunc_idx = cdf_idx;
ectx->ec_instr = INSTRUCTIONS(dfunc);
@@ -556,6 +558,9 @@ func_return(ectx_T *ectx)
}
}
#endif
// TODO: when is it safe to delete the function when it is no longer used?
--dfunc->df_ufunc->uf_calls;
// execution context goes one level up
entry = estack_pop();
if (entry != NULL)
@@ -1334,7 +1339,7 @@ call_def_function(
++ectx.ec_stack.ga_len;
}
if (ufunc->uf_va_name != NULL)
++ectx.ec_stack.ga_len;
++ectx.ec_stack.ga_len;
// Frame pointer points to just after arguments.
ectx.ec_frame_idx = ectx.ec_stack.ga_len;
@@ -1407,6 +1412,9 @@ call_def_function(
// Do turn errors into exceptions.
suppress_errthrow = FALSE;
// Do not delete the function while executing it.
++ufunc->uf_calls;
// When ":silent!" was used before calling then we still abort the
// function. If ":silent!" is used in the function then we don't.
emsg_silent_def = emsg_silent;
@@ -3838,6 +3846,9 @@ failed:
estack_pop();
current_sctx = save_current_sctx;
// TODO: when is it safe to delete the function if it is no longer used?
--ufunc->uf_calls;
if (*msg_list != NULL && saved_msg_list != NULL)
{
msglist_T **plist = saved_msg_list;