mirror of
https://github.com/vim/vim.git
synced 2025-09-24 03:44:06 -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:
@@ -2375,6 +2375,7 @@ eval_variable(
|
|||||||
{
|
{
|
||||||
int ret = OK;
|
int ret = OK;
|
||||||
typval_T *tv = NULL;
|
typval_T *tv = NULL;
|
||||||
|
int foundFunc = FALSE;
|
||||||
dictitem_T *v;
|
dictitem_T *v;
|
||||||
int cc;
|
int cc;
|
||||||
|
|
||||||
@@ -2402,21 +2403,36 @@ eval_variable(
|
|||||||
// imported variable from another script
|
// imported variable from another script
|
||||||
if (import != NULL)
|
if (import != NULL)
|
||||||
{
|
{
|
||||||
scriptitem_T *si = SCRIPT_ITEM(import->imp_sid);
|
if (import->imp_funcname != NULL)
|
||||||
svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data)
|
{
|
||||||
|
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;
|
+ import->imp_var_vals_idx;
|
||||||
tv = sv->sv_tv;
|
tv = sv->sv_tv;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tv == NULL)
|
if (!foundFunc)
|
||||||
{
|
{
|
||||||
if (rettv != NULL && verbose)
|
if (tv == NULL)
|
||||||
semsg(_(e_undefvar), name);
|
{
|
||||||
ret = FAIL;
|
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;
|
name[len] = cc;
|
||||||
|
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
/* scriptfile.c */
|
/* scriptfile.c */
|
||||||
void estack_init(void);
|
void estack_init(void);
|
||||||
estack_T *estack_push(etype_T type, char_u *name, long lnum);
|
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);
|
int estack_top_is_ufunc(ufunc_T *ufunc, long lnum);
|
||||||
void estack_pop(void);
|
estack_T *estack_pop(void);
|
||||||
char_u *estack_sfile(void);
|
char_u *estack_sfile(void);
|
||||||
void ex_runtime(exarg_T *eap);
|
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);
|
int do_in_path(char_u *path, char_u *name, int flags, void (*callback)(char_u *fname, void *ck), void *cookie);
|
||||||
|
@@ -68,7 +68,7 @@ estack_push(etype_T type, char_u *name, long lnum)
|
|||||||
/*
|
/*
|
||||||
* Add a user function to the execution stack.
|
* Add a user function to the execution stack.
|
||||||
*/
|
*/
|
||||||
void
|
estack_T *
|
||||||
estack_push_ufunc(ufunc_T *ufunc, long lnum)
|
estack_push_ufunc(ufunc_T *ufunc, long lnum)
|
||||||
{
|
{
|
||||||
estack_T *entry = estack_push(ETYPE_UFUNC,
|
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);
|
? ufunc->uf_name_exp : ufunc->uf_name, lnum);
|
||||||
if (entry != NULL)
|
if (entry != NULL)
|
||||||
entry->es_info.ufunc = ufunc;
|
entry->es_info.ufunc = ufunc;
|
||||||
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -97,13 +98,15 @@ estack_top_is_ufunc(ufunc_T *ufunc, long lnum)
|
|||||||
#endif
|
#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)
|
estack_pop(void)
|
||||||
{
|
{
|
||||||
if (exestack.ga_len > 1)
|
if (exestack.ga_len == 0)
|
||||||
--exestack.ga_len;
|
return NULL;
|
||||||
|
--exestack.ga_len;
|
||||||
|
return ((estack_T *)exestack.ga_data) + exestack.ga_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -1905,6 +1905,9 @@ typedef struct {
|
|||||||
AutoPatCmd *aucmd; // autocommand info
|
AutoPatCmd *aucmd; // autocommand info
|
||||||
except_T *except; // exception info
|
except_T *except; // exception info
|
||||||
} es_info;
|
} es_info;
|
||||||
|
#if defined(FEAT_EVAL)
|
||||||
|
scid_T es_save_sid; // saved sc_sid when calling function
|
||||||
|
#endif
|
||||||
} estack_T;
|
} estack_T;
|
||||||
|
|
||||||
// Information returned by get_tty_info().
|
// Information returned by get_tty_info().
|
||||||
|
@@ -911,10 +911,10 @@ func Test_import_fails_without_script()
|
|||||||
CheckRunVimInTerminal
|
CheckRunVimInTerminal
|
||||||
|
|
||||||
" call indirectly to avoid compilation error for missing functions
|
" 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
|
endfunc
|
||||||
|
|
||||||
def Run_Test_import_fails_without_script()
|
def Run_Test_import_fails_on_command_line()
|
||||||
let export =<< trim END
|
let export =<< trim END
|
||||||
vim9script
|
vim9script
|
||||||
export def Foo(): number
|
export def Foo(): number
|
||||||
@@ -1013,6 +1013,35 @@ def Test_vim9script_funcref()
|
|||||||
delete('Xscript.vim')
|
delete('Xscript.vim')
|
||||||
enddef
|
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()
|
def Test_vim9script_reload_delfunc()
|
||||||
let first_lines =<< trim END
|
let first_lines =<< trim END
|
||||||
vim9script
|
vim9script
|
||||||
|
@@ -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 */
|
||||||
|
/**/
|
||||||
|
1154,
|
||||||
/**/
|
/**/
|
||||||
1153,
|
1153,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -160,6 +160,7 @@ call_dfunc(int cdf_idx, int argcount_arg, ectx_T *ectx)
|
|||||||
int arg_to_add;
|
int arg_to_add;
|
||||||
int vararg_count = 0;
|
int vararg_count = 0;
|
||||||
int idx;
|
int idx;
|
||||||
|
estack_T *entry;
|
||||||
|
|
||||||
if (dfunc->df_deleted)
|
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.
|
// Set execution state to the start of the called function.
|
||||||
ectx->ec_dfunc_idx = cdf_idx;
|
ectx->ec_dfunc_idx = cdf_idx;
|
||||||
ectx->ec_instr = dfunc->df_instr;
|
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.
|
// Decide where to start execution, handles optional arguments.
|
||||||
init_instr_idx(ufunc, argcount, ectx);
|
init_instr_idx(ufunc, argcount, ectx);
|
||||||
@@ -386,9 +394,12 @@ func_return(ectx_T *ectx)
|
|||||||
+ ectx->ec_dfunc_idx;
|
+ ectx->ec_dfunc_idx;
|
||||||
int argcount = ufunc_argcount(dfunc->df_ufunc);
|
int argcount = ufunc_argcount(dfunc->df_ufunc);
|
||||||
int top = ectx->ec_frame_idx - argcount;
|
int top = ectx->ec_frame_idx - argcount;
|
||||||
|
estack_T *entry;
|
||||||
|
|
||||||
// execution context goes one level up
|
// 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)
|
if (handle_closure_in_use(ectx, TRUE) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
Reference in New Issue
Block a user