Patch 9.0.1320
Problem: Checking the type of a null object causes a crash.
Solution: Don't try to get the class of a null object. (closes #12005)
Handle error from calling a user function better.
Files: src/vim9type.c, src/vim.h, src/userfunc.c, src/proto/userfunc.pro,
src/evalfunc.c, src/proto/evalfunc.pro, src/vim9execute.c,
src/if_lua.c, src/testdir/test_vim9_class.vim
*** ../vim-9.0.1319/src/vim9type.c 2023-01-26 11:58:39.610071592 +0000
--- src/vim9type.c 2023-02-18 13:23:05.737830569 +0000
***************
*** 1659,1665 ****
if (type->tt_type == VAR_OBJECT || type->tt_type == VAR_CLASS)
{
! char_u *class_name = ((class_T *)type->tt_member)->class_name;
size_t len = STRLEN(name) + STRLEN(class_name) + 3;
*tofree = alloc(len);
if (*tofree != NULL)
--- 1659,1666 ----
if (type->tt_type == VAR_OBJECT || type->tt_type == VAR_CLASS)
{
! char_u *class_name = type->tt_member == NULL ? (char_u *)"Unknown"
! : ((class_T *)type->tt_member)->class_name;
size_t len = STRLEN(name) + STRLEN(class_name) + 3;
*tofree = alloc(len);
if (*tofree != NULL)
*** ../vim-9.0.1319/src/vim.h 2023-01-24 12:33:58.950777425 +0000
--- src/vim.h 2023-02-18 14:06:29.718612316 +0000
***************
*** 2270,2275 ****
--- 2270,2289 ----
KEYPROTOCOL_FAIL
} keyprot_T;
+ // errors for when calling a function
+ typedef enum {
+ FCERR_NONE, // no error
+ FCERR_UNKNOWN, // unknown function
+ FCERR_TOOMANY, // too many arguments
+ FCERR_TOOFEW, // too few arguments
+ FCERR_SCRIPT, // missing script context
+ FCERR_DICT, // missing dict
+ FCERR_OTHER, // another kind of error
+ FCERR_DELETED, // function was deleted
+ FCERR_NOTMETHOD, // function cannot be used as a method
+ FCERR_FAILED, // error while executing the function
+ } funcerror_T;
+
// Flags for assignment functions.
#define ASSIGN_VAR 0 // ":var" (nothing special)
#define ASSIGN_FINAL 0x01 // ":final"
***************
*** 2703,2719 ****
#define DO_NOT_FREE_CNT 99999 // refcount for dict or list that should not
// be freed.
- // errors for when calling a function
- #define FCERR_UNKNOWN 0
- #define FCERR_TOOMANY 1
- #define FCERR_TOOFEW 2
- #define FCERR_SCRIPT 3
- #define FCERR_DICT 4
- #define FCERR_NONE 5
- #define FCERR_OTHER 6
- #define FCERR_DELETED 7
- #define FCERR_NOTMETHOD 8 // function cannot be used as a method
-
// fixed buffer length for fname_trans_sid()
#define FLEN_FIXED 40
--- 2717,2722 ----
*** ../vim-9.0.1319/src/userfunc.c 2023-01-26 11:58:39.606071598 +0000
--- src/userfunc.c 2023-02-18 14:39:21.944707089 +0000
***************
*** 1979,1985 ****
* and set "tofree".
*/
char_u *
! fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error)
{
int llen;
char_u *fname;
--- 1979,1989 ----
* and set "tofree".
*/
char_u *
! fname_trans_sid(
! char_u *name,
! char_u *fname_buf,
! char_u **tofree,
! funcerror_T *error)
{
int llen;
char_u *fname;
***************
*** 2716,2722 ****
/*
* Call a user function.
*/
! static void
call_user_func(
ufunc_T *fp, // pointer to function
int argcount, // nr of args
--- 2720,2726 ----
/*
* Call a user function.
*/
! static funcerror_T
call_user_func(
ufunc_T *fp, // pointer to function
int argcount, // nr of args
***************
*** 2731,2736 ****
--- 2735,2741 ----
int save_sticky_cmdmod_flags = sticky_cmdmod_flags;
funccall_T *fc;
int save_did_emsg;
+ funcerror_T retval = FCERR_NONE;
int default_arg_err = FALSE;
dictitem_T *v;
int fixvar_idx = 0; // index in fc_fixvar[]
***************
*** 2755,2768 ****
{
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = -1;
! return;
}
line_breakcheck(); // check for CTRL-C hit
fc = create_funccal(fp, rettv);
if (fc == NULL)
! return;
fc->fc_level = ex_nesting_level;
// Check if this function has a breakpoint.
fc->fc_breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name, (linenr_T)0);
--- 2760,2773 ----
{
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = -1;
! return FCERR_FAILED;
}
line_breakcheck(); // check for CTRL-C hit
fc = create_funccal(fp, rettv);
if (fc == NULL)
! return FCERR_OTHER;
fc->fc_level = ex_nesting_level;
// Check if this function has a breakpoint.
fc->fc_breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name, (linenr_T)0);
***************
*** 2781,2788 ****
profile_may_start_func(&profile_info, fp, caller);
#endif
sticky_cmdmod_flags = 0;
! call_def_function(fp, argcount, argvars, 0,
! funcexe->fe_partial, funcexe->fe_object, fc, rettv);
funcdepth_decrement();
#ifdef FEAT_PROFILE
if (do_profiling == PROF_YES && (fp->uf_profiling
--- 2786,2794 ----
profile_may_start_func(&profile_info, fp, caller);
#endif
sticky_cmdmod_flags = 0;
! if (call_def_function(fp, argcount, argvars, 0,
! funcexe->fe_partial, funcexe->fe_object, fc, rettv) == FAIL)
! retval = FCERR_FAILED;
funcdepth_decrement();
#ifdef FEAT_PROFILE
if (do_profiling == PROF_YES && (fp->uf_profiling
***************
*** 2791,2797 ****
#endif
remove_funccal();
sticky_cmdmod_flags = save_sticky_cmdmod_flags;
! return;
}
islambda = fp->uf_flags & FC_LAMBDA;
--- 2797,2803 ----
#endif
remove_funccal();
sticky_cmdmod_flags = save_sticky_cmdmod_flags;
! return retval;
}
islambda = fp->uf_flags & FC_LAMBDA;
***************
*** 3024,3030 ****
--- 3030,3039 ----
did_emsg = FALSE;
if (default_arg_err && (fp->uf_flags & FC_ABORT))
+ {
did_emsg = TRUE;
+ retval = FCERR_FAILED;
+ }
else if (islambda)
{
char_u *p = *(char_u **)fp->uf_lines.ga_data + 7;
***************
*** 3051,3056 ****
--- 3060,3066 ----
clear_tv(rettv);
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = -1;
+ retval = FCERR_FAILED;
}
#ifdef FEAT_PROFILE
***************
*** 3134,3146 ****
for (i = 0; i < tv_to_free_len; ++i)
clear_tv(tv_to_free[i]);
cleanup_function_call(fc);
}
/*
* Check the argument count for user function "fp".
* Return FCERR_UNKNOWN if OK, FCERR_TOOFEW or FCERR_TOOMANY otherwise.
*/
! int
check_user_func_argcount(ufunc_T *fp, int argcount)
{
int regular_args = fp->uf_args.ga_len;
--- 3144,3158 ----
for (i = 0; i < tv_to_free_len; ++i)
clear_tv(tv_to_free[i]);
cleanup_function_call(fc);
+
+ return retval;
}
/*
* Check the argument count for user function "fp".
* Return FCERR_UNKNOWN if OK, FCERR_TOOFEW or FCERR_TOOMANY otherwise.
*/
! funcerror_T
check_user_func_argcount(ufunc_T *fp, int argcount)
{
int regular_args = fp->uf_args.ga_len;
***************
*** 3155,3161 ****
/*
* Call a user function after checking the arguments.
*/
! int
call_user_func_check(
ufunc_T *fp,
int argcount,
--- 3167,3173 ----
/*
* Call a user function after checking the arguments.
*/
! funcerror_T
call_user_func_check(
ufunc_T *fp,
int argcount,
***************
*** 3164,3170 ****
funcexe_T *funcexe,
dict_T *selfdict)
{
! int error;
#ifdef FEAT_LUA
if (fp->uf_flags & FC_CFUNC)
--- 3176,3182 ----
funcexe_T *funcexe,
dict_T *selfdict)
{
! funcerror_T error = FCERR_NONE;
#ifdef FEAT_LUA
if (fp->uf_flags & FC_CFUNC)
***************
*** 3180,3187 ****
--- 3192,3202 ----
error = check_user_func_argcount(fp, argcount);
if (error != FCERR_UNKNOWN)
return error;
+
if ((fp->uf_flags & FC_DICT) && selfdict == NULL)
+ {
error = FCERR_DICT;
+ }
else
{
int did_save_redo = FALSE;
***************
*** 3199,3205 ****
did_save_redo = TRUE;
}
++fp->uf_calls;
! call_user_func(fp, argcount, argvars, rettv, funcexe,
(fp->uf_flags & FC_DICT) ? selfdict : NULL);
if (--fp->uf_calls <= 0 && fp->uf_refcount <= 0)
// Function was unreferenced while being used, free it now.
--- 3214,3220 ----
did_save_redo = TRUE;
}
++fp->uf_calls;
! error = call_user_func(fp, argcount, argvars, rettv, funcexe,
(fp->uf_flags & FC_DICT) ? selfdict : NULL);
if (--fp->uf_calls <= 0 && fp->uf_refcount <= 0)
// Function was unreferenced while being used, free it now.
***************
*** 3207,3214 ****
if (did_save_redo)
restoreRedobuff(&save_redo);
restore_search_patterns();
- error = FCERR_NONE;
}
return error;
}
--- 3222,3229 ----
if (did_save_redo)
restoreRedobuff(&save_redo);
restore_search_patterns();
}
+
return error;
}
***************
*** 3542,3548 ****
* Nothing if "error" is FCERR_NONE.
*/
void
! user_func_error(int error, char_u *name, int found_var)
{
switch (error)
{
--- 3557,3563 ----
* Nothing if "error" is FCERR_NONE.
*/
void
! user_func_error(funcerror_T error, char_u *name, int found_var)
{
switch (error)
{
***************
*** 3571,3576 ****
--- 3586,3597 ----
emsg_funcname(e_calling_dict_function_without_dictionary_str,
name);
break;
+ case FCERR_OTHER:
+ case FCERR_FAILED:
+ // assume the error message was already given
+ break;
+ case FCERR_NONE:
+ break;
}
}
***************
*** 3591,3597 ****
funcexe_T *funcexe) // more arguments
{
int ret = FAIL;
! int error = FCERR_NONE;
int i;
ufunc_T *fp = NULL;
char_u fname_buf[FLEN_FIXED + 1];
--- 3612,3618 ----
funcexe_T *funcexe) // more arguments
{
int ret = FAIL;
! funcerror_T error = FCERR_NONE;
int i;
ufunc_T *fp = NULL;
char_u fname_buf[FLEN_FIXED + 1];
***************
*** 3823,3829 ****
typval_T *rettv) // return value goes here
{
int ret = FAIL;
! int error = FCERR_NONE;
char_u fname_buf[FLEN_FIXED + 1];
char_u *tofree = NULL;
char_u *name;
--- 3844,3850 ----
typval_T *rettv) // return value goes here
{
int ret = FAIL;
! funcerror_T error = FCERR_NONE;
char_u fname_buf[FLEN_FIXED + 1];
char_u *tofree = NULL;
char_u *name;
***************
*** 5973,5980 ****
// we tolerate an unknown function here, it might be defined later
if (ufunc != NULL)
{
! int error = check_user_func_argcount(ufunc, argcount);
!
if (error != FCERR_UNKNOWN)
{
user_func_error(error, name, FALSE);
--- 5994,6000 ----
// we tolerate an unknown function here, it might be defined later
if (ufunc != NULL)
{
! funcerror_T error = check_user_func_argcount(ufunc, argcount);
if (error != FCERR_UNKNOWN)
{
user_func_error(error, name, FALSE);
***************
*** 6449,6455 ****
char_u *fname;
ufunc_T *fp = NULL;
char_u fname_buf[FLEN_FIXED + 1];
- int error;
dict_T *selfdict = selfdict_in;
if (rettv->v_type == VAR_PARTIAL && rettv->vval.v_partial != NULL
--- 6469,6474 ----
***************
*** 6470,6475 ****
--- 6489,6495 ----
else
{
char_u *tofree = NULL;
+ funcerror_T error;
// Translate "s:func" to the stored function name.
fname = fname_trans_sid(fname, fname_buf, &tofree, &error);
***************
*** 6881,6887 ****
{
ufunc_T *fp = fp_in;
funccall_T *fc;
! int error = FCERR_NONE;
char_u fname_buf[FLEN_FIXED + 1];
char_u *tofree = NULL;
char_u *fname;
--- 6901,6907 ----
{
ufunc_T *fp = fp_in;
funccall_T *fc;
! funcerror_T error = FCERR_NONE;
char_u fname_buf[FLEN_FIXED + 1];
char_u *tofree = NULL;
char_u *fname;
*** ../vim-9.0.1319/src/proto/userfunc.pro 2023-01-08 19:54:06.952281443
+0000
--- src/proto/userfunc.pro 2023-02-18 14:04:17.330730515 +0000
***************
*** 9,15 ****
void emsg_funcname(char *ermsg, char_u *name);
int get_func_arguments(char_u **arg, evalarg_T *evalarg, int partial_argc,
typval_T *argvars, int *argcount);
int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg,
evalarg_T *evalarg, funcexe_T *funcexe);
! char_u *fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int
*error);
void func_name_with_sid(char_u *name, int sid, char_u *buffer);
ufunc_T *find_func_even_dead(char_u *name, int flags);
ufunc_T *find_func(char_u *name, int is_global);
--- 9,15 ----
void emsg_funcname(char *ermsg, char_u *name);
int get_func_arguments(char_u **arg, evalarg_T *evalarg, int partial_argc,
typval_T *argvars, int *argcount);
int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg,
evalarg_T *evalarg, funcexe_T *funcexe);
! char_u *fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree,
funcerror_T *error);
void func_name_with_sid(char_u *name, int sid, char_u *buffer);
ufunc_T *find_func_even_dead(char_u *name, int flags);
ufunc_T *find_func(char_u *name, int is_global);
***************
*** 24,31 ****
void funcdepth_restore(int depth);
funccall_T *create_funccal(ufunc_T *fp, typval_T *rettv);
void remove_funccal(void);
! int check_user_func_argcount(ufunc_T *fp, int argcount);
! int call_user_func_check(ufunc_T *fp, int argcount, typval_T *argvars,
typval_T *rettv, funcexe_T *funcexe, dict_T *selfdict);
void save_funccal(funccal_entry_T *entry);
void restore_funccal(void);
funccall_T *get_current_funccal(void);
--- 24,31 ----
void funcdepth_restore(int depth);
funccall_T *create_funccal(ufunc_T *fp, typval_T *rettv);
void remove_funccal(void);
! funcerror_T check_user_func_argcount(ufunc_T *fp, int argcount);
! funcerror_T call_user_func_check(ufunc_T *fp, int argcount, typval_T
*argvars, typval_T *rettv, funcexe_T *funcexe, dict_T *selfdict);
void save_funccal(funccal_entry_T *entry);
void restore_funccal(void);
funccall_T *get_current_funccal(void);
***************
*** 37,43 ****
int get_callback_depth(void);
int call_callback(callback_T *callback, int len, typval_T *rettv, int
argcount, typval_T *argvars);
varnumber_T call_callback_retnr(callback_T *callback, int argcount, typval_T
*argvars);
! void user_func_error(int error, char_u *name, int found_var);
int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in,
typval_T *argvars_in, funcexe_T *funcexe);
int call_simple_func(char_u *funcname, int len, typval_T *rettv);
char_u *printable_func_name(ufunc_T *fp);
--- 37,43 ----
int get_callback_depth(void);
int call_callback(callback_T *callback, int len, typval_T *rettv, int
argcount, typval_T *argvars);
varnumber_T call_callback_retnr(callback_T *callback, int argcount, typval_T
*argvars);
! void user_func_error(funcerror_T error, char_u *name, int found_var);
int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in,
typval_T *argvars_in, funcexe_T *funcexe);
int call_simple_func(char_u *funcname, int len, typval_T *rettv);
char_u *printable_func_name(ufunc_T *fp);
*** ../vim-9.0.1319/src/evalfunc.c 2023-01-27 21:03:08.895101849 +0000
--- src/evalfunc.c 2023-02-18 13:42:37.625677798 +0000
***************
*** 3056,3063 ****
int
check_internal_func(int idx, int argcount)
{
! int res;
! char *name;
if (argcount < global_functions[idx].f_min_argc)
res = FCERR_TOOFEW;
--- 3056,3063 ----
int
check_internal_func(int idx, int argcount)
{
! funcerror_T res;
! char *name;
if (argcount < global_functions[idx].f_min_argc)
res = FCERR_TOOFEW;
***************
*** 3074,3080 ****
return -1;
}
! int
call_internal_func(
char_u *name,
int argcount,
--- 3074,3080 ----
return -1;
}
! funcerror_T
call_internal_func(
char_u *name,
int argcount,
***************
*** 3107,3113 ****
/*
* Invoke a method for base->method().
*/
! int
call_internal_method(
char_u *name,
int argcount,
--- 3107,3113 ----
/*
* Invoke a method for base->method().
*/
! funcerror_T
call_internal_method(
char_u *name,
int argcount,
*** ../vim-9.0.1319/src/proto/evalfunc.pro 2023-01-15 18:17:08.785655216
+0000
--- src/proto/evalfunc.pro 2023-02-18 14:04:28.266720313 +0000
***************
*** 10,18 ****
type_T *internal_func_ret_type(int idx, int argcount, type2_T *argtypes,
type_T **decl_type, garray_T *type_gap);
int internal_func_is_map(int idx);
int check_internal_func(int idx, int argcount);
! int call_internal_func(char_u *name, int argcount, typval_T *argvars,
typval_T *rettv);
void call_internal_func_by_idx(int idx, typval_T *argvars, typval_T *rettv);
! int call_internal_method(char_u *name, int argcount, typval_T *argvars,
typval_T *rettv, typval_T *basetv);
int non_zero_arg(typval_T *argvars);
buf_T *get_buf_arg(typval_T *arg);
win_T *get_optional_window(typval_T *argvars, int idx);
--- 10,18 ----
type_T *internal_func_ret_type(int idx, int argcount, type2_T *argtypes,
type_T **decl_type, garray_T *type_gap);
int internal_func_is_map(int idx);
int check_internal_func(int idx, int argcount);
! funcerror_T call_internal_func(char_u *name, int argcount, typval_T *argvars,
typval_T *rettv);
void call_internal_func_by_idx(int idx, typval_T *argvars, typval_T *rettv);
! funcerror_T call_internal_method(char_u *name, int argcount, typval_T
*argvars, typval_T *rettv, typval_T *basetv);
int non_zero_arg(typval_T *argvars);
buf_T *get_buf_arg(typval_T *arg);
win_T *get_optional_window(typval_T *argvars, int idx);
*** ../vim-9.0.1319/src/vim9execute.c 2023-02-10 15:52:21.654002123 +0000
--- src/vim9execute.c 2023-02-18 13:49:30.224115508 +0000
***************
*** 1283,1289 ****
{
typval_T argvars[MAX_FUNC_ARGS];
funcexe_T funcexe;
! int error;
int idx;
int did_emsg_before = did_emsg;
compiletype_T compile_type = get_compile_type(ufunc);
--- 1283,1289 ----
{
typval_T argvars[MAX_FUNC_ARGS];
funcexe_T funcexe;
! funcerror_T error;
int idx;
int did_emsg_before = did_emsg;
compiletype_T compile_type = get_compile_type(ufunc);
***************
*** 1464,1473 ****
name = tv->vval.v_string;
if (name != NULL)
{
! char_u fname_buf[FLEN_FIXED + 1];
! char_u *tofree = NULL;
! int error = FCERR_NONE;
! char_u *fname;
// May need to translate <SNR>123_ to K_SNR.
fname = fname_trans_sid(name, fname_buf, &tofree, &error);
--- 1464,1473 ----
name = tv->vval.v_string;
if (name != NULL)
{
! char_u fname_buf[FLEN_FIXED + 1];
! char_u *tofree = NULL;
! funcerror_T error = FCERR_NONE;
! char_u *fname;
// May need to translate <SNR>123_ to K_SNR.
fname = fname_trans_sid(name, fname_buf, &tofree, &error);
*** ../vim-9.0.1319/src/if_lua.c 2023-01-22 21:14:32.617863616 +0000
--- src/if_lua.c 2023-02-18 14:12:50.290319864 +0000
***************
*** 2776,2786 ****
if (lua_pcall(funcstate->L, luaargcount, 1, 0))
{
luaV_emsg(funcstate->L);
! return FCERR_OTHER;
}
luaV_checktypval(funcstate->L, -1, rettv, "get return value");
! return FCERR_NONE;
}
/*
--- 2776,2786 ----
if (lua_pcall(funcstate->L, luaargcount, 1, 0))
{
luaV_emsg(funcstate->L);
! return (int)FCERR_OTHER;
}
luaV_checktypval(funcstate->L, -1, rettv, "get return value");
! return (int)FCERR_NONE;
}
/*
*** ../vim-9.0.1319/src/testdir/test_vim9_class.vim 2023-02-17
21:29:53.558764886 +0000
--- src/testdir/test_vim9_class.vim 2023-02-18 14:16:34.258168238 +0000
***************
*** 195,200 ****
--- 195,220 ----
echo db[state.value]
END
v9.CheckScriptFailure(lines, 'E1360:')
+
+ lines =<< trim END
+ vim9script
+
+ class Background
+ this.background = 'dark'
+ endclass
+
+ class Colorscheme
+ this._bg: Background
+
+ def GetBackground(): string
+ return this._bg.background
+ enddef
+ endclass
+
+ var bg: Background # UNINITIALIZED
+ echo Colorscheme.new(bg).GetBackground()
+ END
+ v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected
object<Background> but got object<Unknown>')
enddef
def Test_class_member_initializer()
*** ../vim-9.0.1319/src/version.c 2023-02-18 12:04:34.058087508 +0000
--- src/version.c 2023-02-18 13:24:09.161811255 +0000
***************
*** 697,698 ****
--- 697,700 ----
{ /* Add new patch number below this line */
+ /**/
+ 1320,
/**/
--
hundred-and-one symptoms of being an internet addict:
143. You dream in pallettes of 216 websafe colors.
/// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/vim_dev/20230218144319.9C59E1C07A0%40moolenaar.net.