mirror of
https://github.com/vim/vim.git
synced 2025-09-23 03:43:49 -04:00
patch 8.2.1202: Vim9: crash when calling a closure from a builtin function
Problem: Vim9: crash when calling a closure from a builtin function. Solution: Use the current execution context. (closes #6441)
This commit is contained in:
@@ -1019,5 +1019,24 @@ def Test_recursive_call()
|
|||||||
assert_equal(6765, Fibonacci(20))
|
assert_equal(6765, Fibonacci(20))
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
def TreeWalk(dir: string): list<any>
|
||||||
|
return readdir(dir)->map({_, val ->
|
||||||
|
fnamemodify(dir .. '/' .. val, ':p')->isdirectory()
|
||||||
|
? {val : TreeWalk(dir .. '/' .. val)}
|
||||||
|
: val
|
||||||
|
})
|
||||||
|
enddef
|
||||||
|
|
||||||
|
def Test_closure_in_map()
|
||||||
|
mkdir('XclosureDir/tdir', 'p')
|
||||||
|
writefile(['111'], 'XclosureDir/file1')
|
||||||
|
writefile(['222'], 'XclosureDir/file2')
|
||||||
|
writefile(['333'], 'XclosureDir/tdir/file3')
|
||||||
|
|
||||||
|
assert_equal(['file1', 'file2', {'tdir': ['file3']}], TreeWalk('XclosureDir'))
|
||||||
|
|
||||||
|
delete('XclosureDir', 'rf')
|
||||||
|
enddef
|
||||||
|
|
||||||
|
|
||||||
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
||||||
|
@@ -754,6 +754,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 */
|
||||||
|
/**/
|
||||||
|
1202,
|
||||||
/**/
|
/**/
|
||||||
1201,
|
1201,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -461,6 +461,10 @@ call_prepare(int argcount, typval_T *argvars, ectx_T *ectx)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ugly global to avoid passing the execution context around through many
|
||||||
|
// layers.
|
||||||
|
static ectx_T *current_ectx = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Call a builtin function by index.
|
* Call a builtin function by index.
|
||||||
*/
|
*/
|
||||||
@@ -470,12 +474,16 @@ call_bfunc(int func_idx, int argcount, ectx_T *ectx)
|
|||||||
typval_T argvars[MAX_FUNC_ARGS];
|
typval_T argvars[MAX_FUNC_ARGS];
|
||||||
int idx;
|
int idx;
|
||||||
int did_emsg_before = did_emsg;
|
int did_emsg_before = did_emsg;
|
||||||
|
ectx_T *prev_ectx = current_ectx;
|
||||||
|
|
||||||
if (call_prepare(argcount, argvars, ectx) == FAIL)
|
if (call_prepare(argcount, argvars, ectx) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
|
||||||
// Call the builtin function.
|
// Call the builtin function. Set "current_ectx" so that when it
|
||||||
|
// recursively invokes call_def_function() a closure context can be set.
|
||||||
|
current_ectx = ectx;
|
||||||
call_internal_func_by_idx(func_idx, argvars, STACK_TV_BOT(-1));
|
call_internal_func_by_idx(func_idx, argvars, STACK_TV_BOT(-1));
|
||||||
|
current_ectx = prev_ectx;
|
||||||
|
|
||||||
// Clear the arguments.
|
// Clear the arguments.
|
||||||
for (idx = 0; idx < argcount; ++idx)
|
for (idx = 0; idx < argcount; ++idx)
|
||||||
@@ -748,10 +756,19 @@ call_def_function(
|
|||||||
initial_frame_idx = ectx.ec_frame_idx;
|
initial_frame_idx = ectx.ec_frame_idx;
|
||||||
|
|
||||||
if (partial != NULL)
|
if (partial != NULL)
|
||||||
|
{
|
||||||
|
if (partial->pt_ectx_stack == NULL && current_ectx != NULL)
|
||||||
|
{
|
||||||
|
// TODO: is this always the right way?
|
||||||
|
ectx.ec_outer_stack = ¤t_ectx->ec_stack;
|
||||||
|
ectx.ec_outer_frame = current_ectx->ec_frame_idx;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
ectx.ec_outer_stack = partial->pt_ectx_stack;
|
ectx.ec_outer_stack = partial->pt_ectx_stack;
|
||||||
ectx.ec_outer_frame = partial->pt_ectx_frame;
|
ectx.ec_outer_frame = partial->pt_ectx_frame;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// dummy frame entries
|
// dummy frame entries
|
||||||
for (idx = 0; idx < STACK_FRAME_SIZE; ++idx)
|
for (idx = 0; idx < STACK_FRAME_SIZE; ++idx)
|
||||||
|
Reference in New Issue
Block a user