To: vim_dev@googlegroups.com Subject: Patch 9.0.1320 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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 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 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 but got object') 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 -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///