Skip to content

Commit bd9155e

Browse files
yegappanchrisbra
authored andcommitted
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>
1 parent 9fff99c commit bd9155e

File tree

3 files changed

+39
-7
lines changed

3 files changed

+39
-7
lines changed

src/testdir/test_vim9_script.vim

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5232,6 +5232,23 @@ def Test_defer_invalid_func_arg()
52325232
v9.CheckScriptFailure(lines, 'E1001: Variable not found: a', 1)
52335233
enddef
52345234

5235+
" Test for using defer with a lambda funcref
5236+
def Test_defer_lambda_funcref()
5237+
var lines =<< trim END
5238+
vim9script
5239+
var lfr_result = ''
5240+
def Foo()
5241+
var Fn = () => {
5242+
lfr_result = 'called'
5243+
}
5244+
defer Fn()
5245+
enddef
5246+
Foo()
5247+
assert_equal('called', lfr_result)
5248+
END
5249+
v9.CheckSourceSuccess(lines)
5250+
enddef
5251+
52355252
" Test for using an non-existing type in a "for" statement.
52365253
def Test_invalid_type_in_for()
52375254
var lines =<< trim END

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,8 @@ static char *(features[]) =
729729

730730
static int included_patches[] =
731731
{ /* Add new patch number below this line */
732+
/**/
733+
1879,
732734
/**/
733735
1878,
734736
/**/

src/vim9execute.c

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1176,20 +1176,30 @@ invoke_defer_funcs(ectx_T *ectx)
11761176
argvars[i] = arg_li->li_tv;
11771177
}
11781178

1179-
funcexe_T funcexe;
1179+
funcexe_T funcexe;
1180+
char_u *name = NULL;
1181+
partial_T *pt = NULL;
1182+
11801183
CLEAR_FIELD(funcexe);
11811184
funcexe.fe_evaluate = TRUE;
11821185
rettv.v_type = VAR_UNKNOWN;
1186+
11831187
if (functv->v_type == VAR_PARTIAL)
11841188
{
1185-
funcexe.fe_partial = functv->vval.v_partial;
1186-
funcexe.fe_object = functv->vval.v_partial->pt_obj;
1189+
pt = functv->vval.v_partial;
1190+
functv->vval.v_partial = NULL;
1191+
1192+
name = pt->pt_func->uf_name;
1193+
funcexe.fe_partial = pt;
1194+
funcexe.fe_object = pt->pt_obj;
11871195
if (funcexe.fe_object != NULL)
11881196
++funcexe.fe_object->obj_refcount;
11891197
}
1190-
1191-
char_u *name = functv->vval.v_string;
1192-
functv->vval.v_string = NULL;
1198+
else
1199+
{
1200+
name = functv->vval.v_string;
1201+
functv->vval.v_string = NULL;
1202+
}
11931203

11941204
// If the deferred function is called after an exception, then only the
11951205
// first statement in the function will be executed (because of the
@@ -1204,7 +1214,10 @@ invoke_defer_funcs(ectx_T *ectx)
12041214
exception_state_restore(&estate);
12051215

12061216
clear_tv(&rettv);
1207-
vim_free(name);
1217+
if (functv->v_type == VAR_PARTIAL)
1218+
partial_unref(pt);
1219+
else
1220+
vim_free(name);
12081221
}
12091222
}
12101223

0 commit comments

Comments
 (0)