diff options
author | Bram Moolenaar <Bram@vim.org> | 2020-07-13 20:41:08 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2020-07-13 20:41:08 +0200 |
commit | 08f7a41b0a280e5901eb4ee4bbfe682113863492 (patch) | |
tree | c5a4c229cde639d8c6518e3dcb79f014ddca90ab /src | |
parent | f1a2368d81fc3f70dfcf7d577957185da6ccf0b6 (diff) | |
download | vim-git-08f7a41b0a280e5901eb4ee4bbfe682113863492.tar.gz |
patch 8.2.1202: Vim9: crash when calling a closure from a builtin functionv8.2.1202
Problem: Vim9: crash when calling a closure from a builtin function.
Solution: Use the current execution context. (closes #6441)
Diffstat (limited to 'src')
-rw-r--r-- | src/testdir/test_vim9_func.vim | 19 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/vim9execute.c | 23 |
3 files changed, 41 insertions, 3 deletions
diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index 99b2a113a..82146756f 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -1019,5 +1019,24 @@ def Test_recursive_call() assert_equal(6765, Fibonacci(20)) 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 diff --git a/src/version.c b/src/version.c index 2c9c4f07a..ddc6f2e06 100644 --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1202, +/**/ 1201, /**/ 1200, diff --git a/src/vim9execute.c b/src/vim9execute.c index 5fdbfbf51..eb900c876 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -461,6 +461,10 @@ call_prepare(int argcount, typval_T *argvars, ectx_T *ectx) 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. */ @@ -470,12 +474,16 @@ call_bfunc(int func_idx, int argcount, ectx_T *ectx) typval_T argvars[MAX_FUNC_ARGS]; int idx; int did_emsg_before = did_emsg; + ectx_T *prev_ectx = current_ectx; if (call_prepare(argcount, argvars, ectx) == 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)); + current_ectx = prev_ectx; // Clear the arguments. for (idx = 0; idx < argcount; ++idx) @@ -749,8 +757,17 @@ call_def_function( if (partial != NULL) { - ectx.ec_outer_stack = partial->pt_ectx_stack; - ectx.ec_outer_frame = partial->pt_ectx_frame; + 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_frame = partial->pt_ectx_frame; + } } // dummy frame entries |