0
0
mirror of https://github.com/vim/vim.git synced 2025-11-14 23:04:02 -05:00

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 <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Yegappan Lakshmanan
2025-10-26 20:03:18 +00:00
committed by Christian Brabandt
parent 9fff99c3c2
commit bd9155ebb6
3 changed files with 39 additions and 7 deletions

View File

@@ -5232,6 +5232,23 @@ def Test_defer_invalid_func_arg()
v9.CheckScriptFailure(lines, 'E1001: Variable not found: a', 1) v9.CheckScriptFailure(lines, 'E1001: Variable not found: a', 1)
enddef 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. " Test for using an non-existing type in a "for" statement.
def Test_invalid_type_in_for() def Test_invalid_type_in_for()
var lines =<< trim END var lines =<< trim END

View File

@@ -729,6 +729,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1879,
/**/ /**/
1878, 1878,
/**/ /**/

View File

@@ -1177,19 +1177,29 @@ invoke_defer_funcs(ectx_T *ectx)
} }
funcexe_T funcexe; funcexe_T funcexe;
char_u *name = NULL;
partial_T *pt = NULL;
CLEAR_FIELD(funcexe); CLEAR_FIELD(funcexe);
funcexe.fe_evaluate = TRUE; funcexe.fe_evaluate = TRUE;
rettv.v_type = VAR_UNKNOWN; rettv.v_type = VAR_UNKNOWN;
if (functv->v_type == VAR_PARTIAL) if (functv->v_type == VAR_PARTIAL)
{ {
funcexe.fe_partial = functv->vval.v_partial; pt = functv->vval.v_partial;
funcexe.fe_object = functv->vval.v_partial->pt_obj; 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) if (funcexe.fe_object != NULL)
++funcexe.fe_object->obj_refcount; ++funcexe.fe_object->obj_refcount;
} }
else
char_u *name = functv->vval.v_string; {
name = functv->vval.v_string;
functv->vval.v_string = NULL; functv->vval.v_string = NULL;
}
// If the deferred function is called after an exception, then only the // If the deferred function is called after an exception, then only the
// first statement in the function will be executed (because of the // first statement in the function will be executed (because of the
@@ -1204,6 +1214,9 @@ invoke_defer_funcs(ectx_T *ectx)
exception_state_restore(&estate); exception_state_restore(&estate);
clear_tv(&rettv); clear_tv(&rettv);
if (functv->v_type == VAR_PARTIAL)
partial_unref(pt);
else
vim_free(name); vim_free(name);
} }
} }