Skip to content

Commit 04c0207

Browse files
committed
Fix a bunch of memory leaks in feature 'class'
* Free the attrlist OP fragment when applying class or field attribute * Free the OP_PADxV ops we only use to get the pad index out for fieldvar declarations * Add a refcount to the `struct padname_fieldinfo` to keep track of its capture in inner closures so it can be freed at the right time * Free the class-related fields out of HvAUX * Free the actual ObjectFIELDS() array when destroying an object instance * Dup fieldinfo->paramname at sv_dup() time / free it at free time
1 parent 7da1927 commit 04c0207

File tree

9 files changed

+113
-45
lines changed

9 files changed

+113
-45
lines changed

class.c

+17-1
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,13 @@ Perl_class_apply_attributes(pTHX_ HV *stash, OP *attrlist)
601601
{
602602
PERL_ARGS_ASSERT_CLASS_APPLY_ATTRIBUTES;
603603

604+
if(!attrlist)
605+
return;
606+
if(attrlist->op_type == OP_NULL) {
607+
op_free(attrlist);
608+
return;
609+
}
610+
604611
if(attrlist->op_type == OP_LIST) {
605612
OP *o = cLISTOPx(attrlist)->op_first;
606613
assert(o->op_type == OP_PUSHMARK);
@@ -611,6 +618,8 @@ Perl_class_apply_attributes(pTHX_ HV *stash, OP *attrlist)
611618
}
612619
else
613620
S_class_apply_attribute(aTHX_ stash, attrlist);
621+
622+
op_free(attrlist);
614623
}
615624

616625
static OP *
@@ -892,6 +901,7 @@ Perl_class_add_field(pTHX_ HV *stash, PADNAME *pn)
892901
Newxz(PadnameFIELDINFO(pn), 1, struct padname_fieldinfo);
893902
PadnameFLAGS(pn) |= PADNAMEf_FIELD;
894903

904+
PadnameFIELDINFO(pn)->refcount = 1;
895905
PadnameFIELDINFO(pn)->fieldix = fieldix;
896906
PadnameFIELDINFO(pn)->fieldstash = (HV *)SvREFCNT_inc(stash);
897907

@@ -972,8 +982,12 @@ Perl_class_apply_field_attributes(pTHX_ PADNAME *pn, OP *attrlist)
972982
{
973983
PERL_ARGS_ASSERT_CLASS_APPLY_FIELD_ATTRIBUTES;
974984

975-
if(!attrlist || attrlist->op_type == OP_NULL)
985+
if(!attrlist)
986+
return;
987+
if(attrlist->op_type == OP_NULL) {
988+
op_free(attrlist);
976989
return;
990+
}
977991

978992
if(attrlist->op_type == OP_LIST) {
979993
OP *o = cLISTOPx(attrlist)->op_first;
@@ -985,6 +999,8 @@ Perl_class_apply_field_attributes(pTHX_ PADNAME *pn, OP *attrlist)
985999
}
9861000
else
9871001
S_class_apply_field_attribute(aTHX_ pn, attrlist);
1002+
1003+
op_free(attrlist);
9881004
}
9891005

9901006
void

hv.c

+17-3
Original file line numberDiff line numberDiff line change
@@ -2278,6 +2278,7 @@ Perl_hv_undef_flags(pTHX_ HV *hv, U32 flags)
22782278
meaning that this structure might be read again at any point in the
22792279
future without further checks or reinitialisation. */
22802280
if (HvHasAUX(hv)) {
2281+
struct xpvhv_aux *aux = HvAUX(hv);
22812282
struct mro_meta *meta;
22822283
const char *name;
22832284

@@ -2295,7 +2296,7 @@ Perl_hv_undef_flags(pTHX_ HV *hv, U32 flags)
22952296
* effective names that need freeing, as well as the usual name. */
22962297
name = HvNAME(hv);
22972298
if (flags & HV_NAME_SETALL
2298-
? cBOOL(HvAUX(hv)->xhv_name_u.xhvnameu_name)
2299+
? cBOOL(aux->xhv_name_u.xhvnameu_name)
22992300
: cBOOL(name))
23002301
{
23012302
if (name && PL_stashcache) {
@@ -2305,7 +2306,7 @@ Perl_hv_undef_flags(pTHX_ HV *hv, U32 flags)
23052306
}
23062307
hv_name_set(hv, NULL, 0, flags);
23072308
}
2308-
if((meta = HvAUX(hv)->xhv_mro_meta)) {
2309+
if((meta = aux->xhv_mro_meta)) {
23092310
if (meta->mro_linear_all) {
23102311
SvREFCNT_dec_NN(meta->mro_linear_all);
23112312
/* mro_linear_current is just acting as a shortcut pointer,
@@ -2319,7 +2320,20 @@ Perl_hv_undef_flags(pTHX_ HV *hv, U32 flags)
23192320
SvREFCNT_dec(meta->isa);
23202321
SvREFCNT_dec(meta->super);
23212322
Safefree(meta);
2322-
HvAUX(hv)->xhv_mro_meta = NULL;
2323+
aux->xhv_mro_meta = NULL;
2324+
}
2325+
2326+
if(HvSTASH_IS_CLASS(hv)) {
2327+
SvREFCNT_dec(aux->xhv_class_superclass);
2328+
SvREFCNT_dec(aux->xhv_class_initfields_cv);
2329+
SvREFCNT_dec(aux->xhv_class_adjust_blocks);
2330+
if(aux->xhv_class_fields)
2331+
PadnamelistREFCNT_dec(aux->xhv_class_fields);
2332+
SvREFCNT_dec(aux->xhv_class_param_map);
2333+
Safefree(aux->xhv_class_suspended_initfields_compcv);
2334+
aux->xhv_class_suspended_initfields_compcv = NULL;
2335+
2336+
aux->xhv_aux_flags &= ~HvAUXf_IS_CLASS;
23232337
}
23242338
}
23252339

pad.c

+14-1
Original file line numberDiff line numberDiff line change
@@ -2803,6 +2803,7 @@ Perl_newPADNAMEouter(PADNAME *outer)
28032803
PadnameFLAGS(pn) = PADNAMEf_OUTER;
28042804
if(PadnameIsFIELD(outer)) {
28052805
PadnameFIELDINFO(pn) = PadnameFIELDINFO(outer);
2806+
PadnameFIELDINFO(pn)->refcount++;
28062807
PadnameFLAGS(pn) |= PADNAMEf_FIELD;
28072808
}
28082809
PadnameLEN(pn) = PadnameLEN(outer);
@@ -2822,6 +2823,16 @@ Perl_padname_free(pTHX_ PADNAME *pn)
28222823
SvREFCNT_dec(PadnameOURSTASH(pn));
28232824
if (PadnameOUTER(pn))
28242825
PadnameREFCNT_dec(PADNAME_FROM_PV(PadnamePV(pn)));
2826+
if (PadnameIsFIELD(pn)) {
2827+
struct padname_fieldinfo *info = PadnameFIELDINFO(pn);
2828+
if(!--info->refcount) {
2829+
SvREFCNT_dec(info->fieldstash);
2830+
/* todo: something about defop */
2831+
SvREFCNT_dec(info->paramname);
2832+
2833+
Safefree(info);
2834+
}
2835+
}
28252836
Safefree(pn);
28262837
}
28272838
}
@@ -2864,13 +2875,15 @@ Perl_padname_dup(pTHX_ PADNAME *src, CLONE_PARAMS *param)
28642875
PadnameTYPE (dst) = (HV *)sv_dup_inc((SV *)PadnameTYPE(src), param);
28652876
PadnameOURSTASH(dst) = (HV *)sv_dup_inc((SV *)PadnameOURSTASH(src),
28662877
param);
2867-
if(PadnameIsFIELD(src)) {
2878+
if(PadnameIsFIELD(src) && !PadnameOUTER(src)) {
28682879
struct padname_fieldinfo *sinfo = PadnameFIELDINFO(src);
28692880
struct padname_fieldinfo *dinfo;
28702881
Newxz(dinfo, 1, struct padname_fieldinfo);
28712882

2883+
dinfo->refcount = 1;
28722884
dinfo->fieldix = sinfo->fieldix;
28732885
dinfo->fieldstash = hv_dup_inc(sinfo->fieldstash, param);
2886+
dinfo->paramname = sv_dup_inc(sinfo->paramname, param);
28742887

28752888
PadnameFIELDINFO(dst) = dinfo;
28762889
}

pad.h

+1
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ struct padname_with_str {
9494
* own substructure, stored in ->xpadn_fieldinfo.
9595
*/
9696
struct padname_fieldinfo {
97+
U32 refcount;
9798
PADOFFSET fieldix; /* index of this field within ObjectFIELDS() array */
9899
HV *fieldstash; /* original class package which added this field */
99100
OP *defop; /* optree fragment for defaulting expression */

perly.act

+39-30
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

perly.h

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)