From bd9155ebb64b3fbf3ff154c8b57c1b3a3783ebea Mon Sep 17 00:00:00 2001 From: Yegappan Lakshmanan Date: Sun, 26 Oct 2025 20:03:18 +0000 Subject: [PATCH] patch 9.1.1879: Crash when using a lambda funcref with :defer Problem: Crash when using a lambda funcref with :defer Solution: De-reference the partial correctly after invoking the deferred functions (Yegappan Lakshmanan). closes: #18640 Signed-off-by: Yegappan Lakshmanan Signed-off-by: Christian Brabandt --- src/testdir/test_vim9_script.vim | 17 +++++++++++++++++ src/version.c | 2 ++ src/vim9execute.c | 27 ++++++++++++++++++++------- 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 3c2c0cc07c..40832a606c 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -5232,6 +5232,23 @@ def Test_defer_invalid_func_arg() v9.CheckScriptFailure(lines, 'E1001: Variable not found: a', 1) enddef +" Test for using defer with a lambda funcref +def Test_defer_lambda_funcref() + var lines =<< trim END + vim9script + var lfr_result = '' + def Foo() + var Fn = () => { + lfr_result = 'called' + } + defer Fn() + enddef + Foo() + assert_equal('called', lfr_result) + END + v9.CheckSourceSuccess(lines) +enddef + " Test for using an non-existing type in a "for" statement. def Test_invalid_type_in_for() var lines =<< trim END diff --git a/src/version.c b/src/version.c index 78860b861b..3f33a0e6fa 100644 --- a/src/version.c +++ b/src/version.c @@ -729,6 +729,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1879, /**/ 1878, /**/ diff --git a/src/vim9execute.c b/src/vim9execute.c index 85606840d4..87a3e9d66f 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -1176,20 +1176,30 @@ invoke_defer_funcs(ectx_T *ectx) argvars[i] = arg_li->li_tv; } - funcexe_T funcexe; + funcexe_T funcexe; + char_u *name = NULL; + partial_T *pt = NULL; + CLEAR_FIELD(funcexe); funcexe.fe_evaluate = TRUE; rettv.v_type = VAR_UNKNOWN; + if (functv->v_type == VAR_PARTIAL) { - funcexe.fe_partial = functv->vval.v_partial; - funcexe.fe_object = functv->vval.v_partial->pt_obj; + pt = functv->vval.v_partial; + functv->vval.v_partial = NULL; + + name = pt->pt_func->uf_name; + funcexe.fe_partial = pt; + funcexe.fe_object = pt->pt_obj; if (funcexe.fe_object != NULL) ++funcexe.fe_object->obj_refcount; } - - char_u *name = functv->vval.v_string; - functv->vval.v_string = NULL; + else + { + name = functv->vval.v_string; + functv->vval.v_string = NULL; + } // If the deferred function is called after an exception, then only the // first statement in the function will be executed (because of the @@ -1204,7 +1214,10 @@ invoke_defer_funcs(ectx_T *ectx) exception_state_restore(&estate); clear_tv(&rettv); - vim_free(name); + if (functv->v_type == VAR_PARTIAL) + partial_unref(pt); + else + vim_free(name); } } -- 2.47.3