From 02c610a9341f8d021c3a039808136f1b0c6694b0 Mon Sep 17 00:00:00 2001 From: Tony Cook Date: Tue, 5 Sep 2023 16:37:48 +1000 Subject: [PATCH] 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 --- class.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/class.c b/class.c index b9dafc3f1a0c..a5b8bf73f132 100644 --- a/class.c +++ b/class.c @@ -634,8 +634,8 @@ Perl_class_seal_stash(pTHX_ HV *stash) assert(HvSTASH_IS_CLASS(stash)); struct xpvhv_aux *aux = HvAUX(stash); - /* generate initfields CV */ - { + if (PL_parser->error_count == 0) { + /* generate initfields CV */ I32 floor_ix = PL_savestack_ix; SAVEI32(PL_subline); save_item(PL_subname); @@ -794,6 +794,18 @@ Perl_class_seal_stash(pTHX_ HV *stash) aux->xhv_class_initfields_cv = initfields; } + else { + /* we had errors, clean up and don't populate initfields */ + PADNAMELIST *fieldnames = aux->xhv_class_fields; + if (fieldnames) { + for(SSize_t i = PadnamelistMAX(fieldnames); i >= 0 ; i--) { + PADNAME *pn = PadnamelistARRAY(fieldnames)[i]; + OP *valop = PadnameFIELDINFO(pn)->defop; + if (valop) + op_free(valop); + } + } + } } void @@ -1010,11 +1022,14 @@ Perl_class_set_field_defop(pTHX_ PADNAME *pn, OPCODE defmode, OP *defop) assert(HvSTASH_IS_CLASS(PL_curstash)); - forbid_outofblock_ops(defop, "field initialiser expression"); - if(PadnameFIELDINFO(pn)->defop) op_free(PadnameFIELDINFO(pn)->defop); + /* set here to ensure clean up if forbid_outofblock_ops() throws */ + PadnameFIELDINFO(pn)->defop = defop; + + forbid_outofblock_ops(defop, "field initialiser expression"); + char sigil = PadnamePV(pn)[0]; switch(sigil) { case '$':