summaryrefslogtreecommitdiff
path: root/op.c
diff options
context:
space:
mode:
authorJarkko Hietaniemi <jhi@iki.fi>2001-03-12 16:04:47 +0000
committerJarkko Hietaniemi <jhi@iki.fi>2001-03-12 16:04:47 +0000
commit282f25c977e1960e4e088425df8229fa6a4a7563 (patch)
tree7a794b96486fbe8f27d0860af1dadc2c79e432aa /op.c
parentfd5f5d222ad399d968d7e5e208df1abd8e5e88ea (diff)
downloadperl-282f25c977e1960e4e088425df8229fa6a4a7563.tar.gz
Integrate change #9108 from maintperl to mainline.
fix memory leak in C<sub X { sub {} }> arising from a refcount loop between the outer sub and the inner prototype anonsub this also enables closures returned by subroutines that subsequently get redefined to work without generating coredumps :) completely removed the free_closures() hack--it shouldn't be needed anymore p4raw-link: @9108 on //depot/maint-5.6/perl: 1cf1f64f42eb50a67f2427ff9d6d24023a2b9997 p4raw-id: //depot/perl@9109 p4raw-branched: from //depot/maint-5.6/perl@9107 'branch in' t/op/anonsub.t p4raw-integrated: from //depot/maint-5.6/perl@9107 'merge in' sv.c (@8871..) embed.h (@8886..) pod/perlapi.pod proto.h (@8993..) embed.pl (@8995..) MANIFEST (@9030..) op.c op.h (@9055..) pp_ctl.c (@9076..)
Diffstat (limited to 'op.c')
-rw-r--r--op.c46
1 files changed, 40 insertions, 6 deletions
diff --git a/op.c b/op.c
index cca2310cd3..421dc9e69d 100644
--- a/op.c
+++ b/op.c
@@ -4158,14 +4158,19 @@ Perl_cv_undef(pTHX_ CV *cv)
SAVEVPTR(PL_curpad);
PL_curpad = 0;
- if (!CvCLONED(cv))
- op_free(CvROOT(cv));
+ op_free(CvROOT(cv));
CvROOT(cv) = Nullop;
LEAVE;
}
SvPOK_off((SV*)cv); /* forget prototype */
CvGV(cv) = Nullgv;
- SvREFCNT_dec(CvOUTSIDE(cv));
+ /* Since closure prototypes have the same lifetime as the containing
+ * CV, they don't hold a refcount on the outside CV. This avoids
+ * the refcount loop between the outer CV (which keeps a refcount to
+ * the closure prototype in the pad entry for pp_anoncode()) and the
+ * closure prototype, and the ensuing memory leak. --GSAR */
+ if (!CvANON(cv) || CvCLONED(cv))
+ SvREFCNT_dec(CvOUTSIDE(cv));
CvOUTSIDE(cv) = Nullcv;
if (CvCONST(cv)) {
SvREFCNT_dec((SV*)CvXSUBANY(cv).any_ptr);
@@ -4279,7 +4284,7 @@ S_cv_clone2(pTHX_ CV *proto, CV *outside)
CvFILE(cv) = CvFILE(proto);
CvGV(cv) = CvGV(proto);
CvSTASH(cv) = CvSTASH(proto);
- CvROOT(cv) = CvROOT(proto);
+ CvROOT(cv) = OpREFCNT_inc(CvROOT(proto));
CvSTART(cv) = CvSTART(proto);
if (outside)
CvOUTSIDE(cv) = (CV*)SvREFCNT_inc(outside);
@@ -4675,8 +4680,30 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
CvOUTSIDE(PL_compcv) = 0;
CvPADLIST(cv) = CvPADLIST(PL_compcv);
CvPADLIST(PL_compcv) = 0;
- if (SvREFCNT(PL_compcv) > 1) /* XXX Make closures transit through stub. */
- CvOUTSIDE(PL_compcv) = (CV*)SvREFCNT_inc((SV*)cv);
+ /* inner references to PL_compcv must be fixed up ... */
+ {
+ AV *padlist = CvPADLIST(cv);
+ AV *comppad_name = (AV*)AvARRAY(padlist)[0];
+ AV *comppad = (AV*)AvARRAY(padlist)[1];
+ SV **namepad = AvARRAY(comppad_name);
+ SV **curpad = AvARRAY(comppad);
+ for (ix = AvFILLp(comppad_name); ix > 0; ix--) {
+ SV *namesv = namepad[ix];
+ if (namesv && namesv != &PL_sv_undef
+ && *SvPVX(namesv) == '&')
+ {
+ CV *innercv = (CV*)curpad[ix];
+ if (CvOUTSIDE(innercv) == PL_compcv) {
+ CvOUTSIDE(innercv) = cv;
+ if (!CvANON(innercv) || CvCLONED(innercv)) {
+ (void)SvREFCNT_inc(cv);
+ SvREFCNT_dec(PL_compcv);
+ }
+ }
+ }
+ }
+ }
+ /* ... before we throw it away */
SvREFCNT_dec(PL_compcv);
}
else {
@@ -4779,6 +4806,13 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
}
}
+ /* If a potential closure prototype, don't keep a refcount on outer CV.
+ * This is okay as the lifetime of the prototype is tied to the
+ * lifetime of the outer CV. Avoids memory leak due to reference
+ * loop. --GSAR */
+ if (!name)
+ SvREFCNT_dec(CvOUTSIDE(cv));
+
if (name || aname) {
char *s;
char *tname = (name ? name : aname);