Skip to content

Commit 02c610a

Browse files
committed
class: don't leak the default initialiser ops if they're forbidden
Previously if forbid_outofblock_ops() here threw an error the ops from defop would leak, including leaking the slab(s) containing those ops. To prevent that, populate the defop for the field with the supplied ops before calling forbid_outofblock_ops(), then as the save stack rewinds class_seal_stash() will check the error count and free the ops. Fixes #20812
1 parent 5e28db9 commit 02c610a

File tree

1 file changed

+19
-4
lines changed

1 file changed

+19
-4
lines changed

class.c

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -634,8 +634,8 @@ Perl_class_seal_stash(pTHX_ HV *stash)
634634
assert(HvSTASH_IS_CLASS(stash));
635635
struct xpvhv_aux *aux = HvAUX(stash);
636636

637-
/* generate initfields CV */
638-
{
637+
if (PL_parser->error_count == 0) {
638+
/* generate initfields CV */
639639
I32 floor_ix = PL_savestack_ix;
640640
SAVEI32(PL_subline);
641641
save_item(PL_subname);
@@ -794,6 +794,18 @@ Perl_class_seal_stash(pTHX_ HV *stash)
794794

795795
aux->xhv_class_initfields_cv = initfields;
796796
}
797+
else {
798+
/* we had errors, clean up and don't populate initfields */
799+
PADNAMELIST *fieldnames = aux->xhv_class_fields;
800+
if (fieldnames) {
801+
for(SSize_t i = PadnamelistMAX(fieldnames); i >= 0 ; i--) {
802+
PADNAME *pn = PadnamelistARRAY(fieldnames)[i];
803+
OP *valop = PadnameFIELDINFO(pn)->defop;
804+
if (valop)
805+
op_free(valop);
806+
}
807+
}
808+
}
797809
}
798810

799811
void
@@ -1010,11 +1022,14 @@ Perl_class_set_field_defop(pTHX_ PADNAME *pn, OPCODE defmode, OP *defop)
10101022

10111023
assert(HvSTASH_IS_CLASS(PL_curstash));
10121024

1013-
forbid_outofblock_ops(defop, "field initialiser expression");
1014-
10151025
if(PadnameFIELDINFO(pn)->defop)
10161026
op_free(PadnameFIELDINFO(pn)->defop);
10171027

1028+
/* set here to ensure clean up if forbid_outofblock_ops() throws */
1029+
PadnameFIELDINFO(pn)->defop = defop;
1030+
1031+
forbid_outofblock_ops(defop, "field initialiser expression");
1032+
10181033
char sigil = PadnamePV(pn)[0];
10191034
switch(sigil) {
10201035
case '$':

0 commit comments

Comments
 (0)