# HG changeset patch # User Bram Moolenaar # Date 1686412806 -7200 # Node ID 2d1eba13035cc383dd52b8eb20eea9d04f294108 # Parent 3a10160f224250e770791a68ea8c094bdc6b9c9c patch 9.0.1624: crash when calling object constructor Commit: https://github.com/vim/vim/commit/5ca05fa59e587f9724306d4788c5dde07fc7225b Author: Bram Moolenaar Date: Sat Jun 10 16:45:13 2023 +0100 patch 9.0.1624: crash when calling object constructor Problem: Crash when calling object constructor from legacy script. (Israel Chauca Fuentes) Solution: Pass a pointer for "ufunc". (closes #12502) diff --git a/src/structs.h b/src/structs.h --- a/src/structs.h +++ b/src/structs.h @@ -2184,7 +2184,9 @@ typedef struct { linenr_T fe_lastline; // last line of range int *fe_doesrange; // if not NULL: return: function handled range int fe_evaluate; // actually evaluate expressions - partial_T *fe_partial; // for extra arguments + ufunc_T *fe_ufunc; // function to be called, when NULL lookup by + // name + partial_T *fe_partial; // for "dict" and extra arguments dict_T *fe_selfdict; // Dictionary for "self" object_T *fe_object; // object, e.g. for "this.Func()" typval_T *fe_basetv; // base for base->method() diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim --- a/src/testdir/test_vim9_class.vim +++ b/src/testdir/test_vim9_class.vim @@ -1767,6 +1767,29 @@ def Test_closure_in_class() v9.CheckScriptSuccess(lines) enddef +def Test_call_constructor_from_legacy() + var lines =<< trim END + vim9script + + var newCalled = 'false' + + class A + def new() + newCalled = 'true' + enddef + endclass + + export def F(options = {}): any + return A + enddef + + g:p = F() + legacy call p.new() + assert_equal('true', newCalled) + END + v9.CheckScriptSuccess(lines) +enddef + def Test_defer_with_object() var lines =<< trim END vim9script diff --git a/src/userfunc.c b/src/userfunc.c --- a/src/userfunc.c +++ b/src/userfunc.c @@ -3666,6 +3666,9 @@ call_func( if (partial != NULL) fp = partial->pt_func; if (fp == NULL) + fp = funcexe->fe_ufunc; + + if (fp == NULL) { // Make a copy of the name, if it comes from a funcref variable it // could be changed or deleted in the called function. @@ -4161,8 +4164,10 @@ trans_function_name_ext( if (lv.ll_ufunc != NULL) { - *ufunc = lv.ll_ufunc; + if (ufunc != NULL) + *ufunc = lv.ll_ufunc; name = vim_strsave(lv.ll_ufunc->uf_name); + *pp = end; goto theend; } @@ -5915,7 +5920,7 @@ ex_call_inner( char_u *name, char_u **arg, char_u *startarg, - funcexe_T *funcexe_init, + funcexe_T *funcexe_init, evalarg_T *evalarg) { linenr_T lnum; @@ -6204,6 +6209,7 @@ ex_call(exarg_T *eap) int len; int failed = FALSE; funcdict_T fudi; + ufunc_T *ufunc = NULL; partial_T *partial = NULL; evalarg_T evalarg; type_T *type = NULL; @@ -6227,7 +6233,7 @@ ex_call(exarg_T *eap) } tofree = trans_function_name_ext(&arg, NULL, FALSE, TFN_INT, - &fudi, &partial, vim9script ? &type : NULL, NULL); + &fudi, &partial, vim9script ? &type : NULL, &ufunc); if (fudi.fd_newkey != NULL) { // Still need to give an error message for missing key. @@ -6275,6 +6281,7 @@ ex_call(exarg_T *eap) CLEAR_FIELD(funcexe); funcexe.fe_check_type = type; + funcexe.fe_ufunc = ufunc; funcexe.fe_partial = partial; funcexe.fe_selfdict = fudi.fd_dict; funcexe.fe_firstline = eap->line1; diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -696,6 +696,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1624, +/**/ 1623, /**/ 1622,