summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-07-08 15:16:19 +0200
committerBram Moolenaar <Bram@vim.org>2020-07-08 15:16:19 +0200
commitc620c055ce8505596a7208ba696a32b8a3be4f4b (patch)
treed61c203d6df6363f0466c4b4b8f4bd14141926c0
parentbed36b939a4c66f41d1f24e32cfa521b10f22b82 (diff)
downloadvim-git-c620c055ce8505596a7208ba696a32b8a3be4f4b.tar.gz
patch 8.2.1154: Vim9: crash when using imported functionv8.2.1154
Problem: Vim9: crash when using imported function. Solution: Check for a function type. Set the script context when calling a function. (closes #6412)
-rw-r--r--src/evalvars.c34
-rw-r--r--src/proto/scriptfile.pro4
-rw-r--r--src/scriptfile.c13
-rw-r--r--src/structs.h3
-rw-r--r--src/testdir/test_vim9_script.vim33
-rw-r--r--src/version.c2
-rw-r--r--src/vim9execute.c15
7 files changed, 84 insertions, 20 deletions
diff --git a/src/evalvars.c b/src/evalvars.c
index 3dab22bb2..9cd2ec2c8 100644
--- a/src/evalvars.c
+++ b/src/evalvars.c
@@ -2375,6 +2375,7 @@ eval_variable(
{
int ret = OK;
typval_T *tv = NULL;
+ int foundFunc = FALSE;
dictitem_T *v;
int cc;
@@ -2402,21 +2403,36 @@ eval_variable(
// imported variable from another script
if (import != NULL)
{
- scriptitem_T *si = SCRIPT_ITEM(import->imp_sid);
- svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data)
+ if (import->imp_funcname != NULL)
+ {
+ foundFunc = TRUE;
+ if (rettv != NULL)
+ {
+ rettv->v_type = VAR_FUNC;
+ rettv->vval.v_string = vim_strsave(import->imp_funcname);
+ }
+ }
+ else
+ {
+ scriptitem_T *si = SCRIPT_ITEM(import->imp_sid);
+ svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data)
+ import->imp_var_vals_idx;
- tv = sv->sv_tv;
+ tv = sv->sv_tv;
+ }
}
}
- if (tv == NULL)
+ if (!foundFunc)
{
- if (rettv != NULL && verbose)
- semsg(_(e_undefvar), name);
- ret = FAIL;
+ if (tv == NULL)
+ {
+ if (rettv != NULL && verbose)
+ semsg(_(e_undefvar), name);
+ ret = FAIL;
+ }
+ else if (rettv != NULL)
+ copy_tv(tv, rettv);
}
- else if (rettv != NULL)
- copy_tv(tv, rettv);
name[len] = cc;
diff --git a/src/proto/scriptfile.pro b/src/proto/scriptfile.pro
index b5b8aae93..fd4c10473 100644
--- a/src/proto/scriptfile.pro
+++ b/src/proto/scriptfile.pro
@@ -1,9 +1,9 @@
/* scriptfile.c */
void estack_init(void);
estack_T *estack_push(etype_T type, char_u *name, long lnum);
-void estack_push_ufunc(ufunc_T *ufunc, long lnum);
+estack_T *estack_push_ufunc(ufunc_T *ufunc, long lnum);
int estack_top_is_ufunc(ufunc_T *ufunc, long lnum);
-void estack_pop(void);
+estack_T *estack_pop(void);
char_u *estack_sfile(void);
void ex_runtime(exarg_T *eap);
int do_in_path(char_u *path, char_u *name, int flags, void (*callback)(char_u *fname, void *ck), void *cookie);
diff --git a/src/scriptfile.c b/src/scriptfile.c
index 9ffc66c1b..ce4bafada 100644
--- a/src/scriptfile.c
+++ b/src/scriptfile.c
@@ -68,7 +68,7 @@ estack_push(etype_T type, char_u *name, long lnum)
/*
* Add a user function to the execution stack.
*/
- void
+ estack_T *
estack_push_ufunc(ufunc_T *ufunc, long lnum)
{
estack_T *entry = estack_push(ETYPE_UFUNC,
@@ -76,6 +76,7 @@ estack_push_ufunc(ufunc_T *ufunc, long lnum)
? ufunc->uf_name_exp : ufunc->uf_name, lnum);
if (entry != NULL)
entry->es_info.ufunc = ufunc;
+ return entry;
}
/*
@@ -97,13 +98,15 @@ estack_top_is_ufunc(ufunc_T *ufunc, long lnum)
#endif
/*
- * Take an item off of the execution stack.
+ * Take an item off of the execution stack and return it.
*/
- void
+ estack_T *
estack_pop(void)
{
- if (exestack.ga_len > 1)
- --exestack.ga_len;
+ if (exestack.ga_len == 0)
+ return NULL;
+ --exestack.ga_len;
+ return ((estack_T *)exestack.ga_data) + exestack.ga_len;
}
/*
diff --git a/src/structs.h b/src/structs.h
index cab6885e4..5c606d883 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -1905,6 +1905,9 @@ typedef struct {
AutoPatCmd *aucmd; // autocommand info
except_T *except; // exception info
} es_info;
+#if defined(FEAT_EVAL)
+ scid_T es_save_sid; // saved sc_sid when calling function
+#endif
} estack_T;
// Information returned by get_tty_info().
diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim
index c1d722865..a95761fc0 100644
--- a/src/testdir/test_vim9_script.vim
+++ b/src/testdir/test_vim9_script.vim
@@ -911,10 +911,10 @@ func Test_import_fails_without_script()
CheckRunVimInTerminal
" call indirectly to avoid compilation error for missing functions
- call Run_Test_import_fails_without_script()
+ call Run_Test_import_fails_on_command_line()
endfunc
-def Run_Test_import_fails_without_script()
+def Run_Test_import_fails_on_command_line()
let export =<< trim END
vim9script
export def Foo(): number
@@ -1013,6 +1013,35 @@ def Test_vim9script_funcref()
delete('Xscript.vim')
enddef
+" Check that when searcing for "FilterFunc" it doesn't find the import in the
+" script where FastFilter() is called from.
+def Test_vim9script_funcref_other_script()
+ let filterLines =<< trim END
+ vim9script
+ export def FilterFunc(idx: number, val: number): bool
+ return idx % 2 == 1
+ enddef
+ export def FastFilter(): list<number>
+ return range(10)->filter('FilterFunc')
+ enddef
+ END
+ writefile(filterLines, 'Xfilter.vim')
+
+ let lines =<< trim END
+ vim9script
+ import {FilterFunc, FastFilter} from './Xfilter.vim'
+ def Test()
+ let x: list<number> = FastFilter()
+ enddef
+ Test()
+ END
+ writefile(lines, 'Ximport.vim')
+ assert_fails('source Ximport.vim', 'E121:')
+
+ delete('Xfilter.vim')
+ delete('Ximport.vim')
+enddef
+
def Test_vim9script_reload_delfunc()
let first_lines =<< trim END
vim9script
diff --git a/src/version.c b/src/version.c
index 0d3e85e54..7633792ed 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 */
/**/
+ 1154,
+/**/
1153,
/**/
1152,
diff --git a/src/vim9execute.c b/src/vim9execute.c
index 7afa3fc5e..a3cea806e 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -160,6 +160,7 @@ call_dfunc(int cdf_idx, int argcount_arg, ectx_T *ectx)
int arg_to_add;
int vararg_count = 0;
int idx;
+ estack_T *entry;
if (dfunc->df_deleted)
{
@@ -230,7 +231,14 @@ call_dfunc(int cdf_idx, int argcount_arg, ectx_T *ectx)
// Set execution state to the start of the called function.
ectx->ec_dfunc_idx = cdf_idx;
ectx->ec_instr = dfunc->df_instr;
- estack_push_ufunc(dfunc->df_ufunc, 1);
+ entry = estack_push_ufunc(dfunc->df_ufunc, 1);
+ if (entry != NULL)
+ {
+ // Set the script context to the script where the function was defined.
+ // TODO: save more than the SID?
+ entry->es_save_sid = current_sctx.sc_sid;
+ current_sctx.sc_sid = ufunc->uf_script_ctx.sc_sid;
+ }
// Decide where to start execution, handles optional arguments.
init_instr_idx(ufunc, argcount, ectx);
@@ -386,9 +394,12 @@ func_return(ectx_T *ectx)
+ ectx->ec_dfunc_idx;
int argcount = ufunc_argcount(dfunc->df_ufunc);
int top = ectx->ec_frame_idx - argcount;
+ estack_T *entry;
// execution context goes one level up
- estack_pop();
+ entry = estack_pop();
+ if (entry != NULL)
+ current_sctx.sc_sid = entry->es_save_sid;
if (handle_closure_in_use(ectx, TRUE) == FAIL)
return FAIL;