patch 9.0.1320: checking the type of a null object causes a crash
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.
diff --git a/src/userfunc.c b/src/userfunc.c
index 1009cd7..d5dd369 100644
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -1979,7 +1979,11 @@
* and set "tofree".
*/
char_u *
-fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error)
+fname_trans_sid(
+ char_u *name,
+ char_u *fname_buf,
+ char_u **tofree,
+ funcerror_T *error)
{
int llen;
char_u *fname;
@@ -2716,7 +2720,7 @@
/*
* Call a user function.
*/
- static void
+ static funcerror_T
call_user_func(
ufunc_T *fp, // pointer to function
int argcount, // nr of args
@@ -2731,6 +2735,7 @@
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,14 +2760,14 @@
{
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = -1;
- return;
+ return FCERR_FAILED;
}
line_breakcheck(); // check for CTRL-C hit
fc = create_funccal(fp, rettv);
if (fc == NULL)
- return;
+ 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,8 +2786,9 @@
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);
+ 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,7 +2797,7 @@
#endif
remove_funccal();
sticky_cmdmod_flags = save_sticky_cmdmod_flags;
- return;
+ return retval;
}
islambda = fp->uf_flags & FC_LAMBDA;
@@ -3024,7 +3030,10 @@
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,6 +3060,7 @@
clear_tv(rettv);
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = -1;
+ retval = FCERR_FAILED;
}
#ifdef FEAT_PROFILE
@@ -3134,13 +3144,15 @@
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.
*/
- int
+ funcerror_T
check_user_func_argcount(ufunc_T *fp, int argcount)
{
int regular_args = fp->uf_args.ga_len;
@@ -3155,7 +3167,7 @@
/*
* Call a user function after checking the arguments.
*/
- int
+ funcerror_T
call_user_func_check(
ufunc_T *fp,
int argcount,
@@ -3164,7 +3176,7 @@
funcexe_T *funcexe,
dict_T *selfdict)
{
- int error;
+ funcerror_T error = FCERR_NONE;
#ifdef FEAT_LUA
if (fp->uf_flags & FC_CFUNC)
@@ -3180,8 +3192,11 @@
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,7 +3214,7 @@
did_save_redo = TRUE;
}
++fp->uf_calls;
- call_user_func(fp, argcount, argvars, rettv, funcexe,
+ 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,8 +3222,8 @@
if (did_save_redo)
restoreRedobuff(&save_redo);
restore_search_patterns();
- error = FCERR_NONE;
}
+
return error;
}
@@ -3542,7 +3557,7 @@
* Nothing if "error" is FCERR_NONE.
*/
void
-user_func_error(int error, char_u *name, int found_var)
+user_func_error(funcerror_T error, char_u *name, int found_var)
{
switch (error)
{
@@ -3571,6 +3586,12 @@
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,7 +3612,7 @@
funcexe_T *funcexe) // more arguments
{
int ret = FAIL;
- int error = FCERR_NONE;
+ funcerror_T error = FCERR_NONE;
int i;
ufunc_T *fp = NULL;
char_u fname_buf[FLEN_FIXED + 1];
@@ -3823,7 +3844,7 @@
typval_T *rettv) // return value goes here
{
int ret = FAIL;
- int error = FCERR_NONE;
+ funcerror_T error = FCERR_NONE;
char_u fname_buf[FLEN_FIXED + 1];
char_u *tofree = NULL;
char_u *name;
@@ -5973,8 +5994,7 @@
// we tolerate an unknown function here, it might be defined later
if (ufunc != NULL)
{
- int error = check_user_func_argcount(ufunc, argcount);
-
+ funcerror_T error = check_user_func_argcount(ufunc, argcount);
if (error != FCERR_UNKNOWN)
{
user_func_error(error, name, FALSE);
@@ -6449,7 +6469,6 @@
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
@@ -6470,6 +6489,7 @@
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,7 +6901,7 @@
{
ufunc_T *fp = fp_in;
funccall_T *fc;
- int error = FCERR_NONE;
+ funcerror_T error = FCERR_NONE;
char_u fname_buf[FLEN_FIXED + 1];
char_u *tofree = NULL;
char_u *fname;