summaryrefslogtreecommitdiff
path: root/pad.c
diff options
context:
space:
mode:
authorPaul "LeoNerd" Evans <leonerd@leonerd.org.uk>2023-02-14 22:50:42 +0000
committerPaul Evans <leonerd@leonerd.org.uk>2023-02-17 21:06:16 +0000
commit04c0207ebb3cb7f894b5f5b6320970aabda477a9 (patch)
treeeb8c26eb2998fb14f91d013b9a7a1618b3b8c7f6 /pad.c
parent7da1927c007a205d378f1913ba5dd4027799926e (diff)
downloadperl-04c0207ebb3cb7f894b5f5b6320970aabda477a9.tar.gz
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
Diffstat (limited to 'pad.c')
-rw-r--r--pad.c15
1 files changed, 14 insertions, 1 deletions
diff --git a/pad.c b/pad.c
index 4b75998cac..1e6449ad69 100644
--- a/pad.c
+++ b/pad.c
@@ -2803,6 +2803,7 @@ Perl_newPADNAMEouter(PADNAME *outer)
PadnameFLAGS(pn) = PADNAMEf_OUTER;
if(PadnameIsFIELD(outer)) {
PadnameFIELDINFO(pn) = PadnameFIELDINFO(outer);
+ PadnameFIELDINFO(pn)->refcount++;
PadnameFLAGS(pn) |= PADNAMEf_FIELD;
}
PadnameLEN(pn) = PadnameLEN(outer);
@@ -2822,6 +2823,16 @@ Perl_padname_free(pTHX_ PADNAME *pn)
SvREFCNT_dec(PadnameOURSTASH(pn));
if (PadnameOUTER(pn))
PadnameREFCNT_dec(PADNAME_FROM_PV(PadnamePV(pn)));
+ if (PadnameIsFIELD(pn)) {
+ struct padname_fieldinfo *info = PadnameFIELDINFO(pn);
+ if(!--info->refcount) {
+ SvREFCNT_dec(info->fieldstash);
+ /* todo: something about defop */
+ SvREFCNT_dec(info->paramname);
+
+ Safefree(info);
+ }
+ }
Safefree(pn);
}
}
@@ -2864,13 +2875,15 @@ Perl_padname_dup(pTHX_ PADNAME *src, CLONE_PARAMS *param)
PadnameTYPE (dst) = (HV *)sv_dup_inc((SV *)PadnameTYPE(src), param);
PadnameOURSTASH(dst) = (HV *)sv_dup_inc((SV *)PadnameOURSTASH(src),
param);
- if(PadnameIsFIELD(src)) {
+ if(PadnameIsFIELD(src) && !PadnameOUTER(src)) {
struct padname_fieldinfo *sinfo = PadnameFIELDINFO(src);
struct padname_fieldinfo *dinfo;
Newxz(dinfo, 1, struct padname_fieldinfo);
+ dinfo->refcount = 1;
dinfo->fieldix = sinfo->fieldix;
dinfo->fieldstash = hv_dup_inc(sinfo->fieldstash, param);
+ dinfo->paramname = sv_dup_inc(sinfo->paramname, param);
PadnameFIELDINFO(dst) = dinfo;
}