0
0
mirror of https://github.com/vim/vim.git synced 2025-09-23 03:43:49 -04:00

patch 8.2.1154: Vim9: crash when using imported function

Problem:    Vim9: crash when using imported function.
Solution:   Check for a function type.  Set the script context when calling a
            function. (closes #6412)
This commit is contained in:
Bram Moolenaar
2020-07-08 15:16:19 +02:00
parent bed36b939a
commit c620c055ce
7 changed files with 84 additions and 20 deletions

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;
}
/*

View File

@@ -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().

View File

@@ -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

View File

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

View File

@@ -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;