Integrate maint patches #13474, #13478, #13584, and #16539;
Jarkko Hietaniemi [Sun, 7 Jul 2002 17:04:27 +0000 (17:04 +0000)]
introduce the test case of [ID 20020623.009].  Once upon a
time #13474 introduced evil coredumps, but now things seem
to be better (tried both with and without ithreads).

p4raw-id: //depot/perl@17407
p4raw-edited: from //depot/maint-5.6/perl@17406 'ignore' op.c
(@14778..)

op.c
t/run/fresh_perl.t

diff --git a/op.c b/op.c
index 9a53f07..850983b 100644 (file)
--- a/op.c
+++ b/op.c
@@ -4348,6 +4348,10 @@ Perl_newLOOPEX(pTHX_ I32 type, OP *label)
 void
 Perl_cv_undef(pTHX_ CV *cv)
 {
+    CV *outsidecv;
+    CV *freecv = Nullcv;
+    bool is_eval = CvEVAL(cv) && !CvGV(cv);    /* is this eval"" ? */
+
 #ifdef USE_5005THREADS
     if (CvMUTEXP(cv)) {
        MUTEX_DESTROY(CvMUTEXP(cv));
@@ -4383,13 +4387,14 @@ Perl_cv_undef(pTHX_ CV *cv)
     }
     SvPOK_off((SV*)cv);                /* forget prototype */
     CvGV(cv) = Nullgv;
+    outsidecv = 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));
+        freecv = outsidecv;
     CvOUTSIDE(cv) = Nullcv;
     if (CvCONST(cv)) {
        SvREFCNT_dec((SV*)CvXSUBANY(cv).any_ptr);
@@ -4398,10 +4403,40 @@ Perl_cv_undef(pTHX_ CV *cv)
     if (CvPADLIST(cv)) {
        /* may be during global destruction */
        if (SvREFCNT(CvPADLIST(cv))) {
-           I32 i = AvFILLp(CvPADLIST(cv));
-           while (i >= 0) {
-               SV** svp = av_fetch(CvPADLIST(cv), i--, FALSE);
-               SV* sv = svp ? *svp : Nullsv;
+           AV *padlist = CvPADLIST(cv);
+           I32 ix;
+           /* pads may be cleared out already during global destruction */
+           if (is_eval && !PL_dirty) {
+               /* inner references to eval's cv must be fixed up */
+               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) == '&'
+                       && ix <= AvFILLp(comppad))
+                   {
+                       CV *innercv = (CV*)curpad[ix];
+                       if (innercv && SvTYPE(innercv) == SVt_PVCV
+                           && CvOUTSIDE(innercv) == cv)
+                       {
+                           CvOUTSIDE(innercv) = outsidecv;
+                           if (!CvANON(innercv) || CvCLONED(innercv)) {
+                               (void)SvREFCNT_inc(outsidecv);
+                               if (SvREFCNT(cv))
+                                   SvREFCNT_dec(cv);
+                           }
+                       }
+                   }
+               }
+           }
+           if (freecv)
+               SvREFCNT_dec(freecv);
+           ix = AvFILLp(padlist);
+           while (ix >= 0) {
+               SV* sv = AvARRAY(padlist)[ix--];
                if (!sv)
                    continue;
                if (sv == (SV*)PL_comppad_name)
@@ -4416,6 +4451,8 @@ Perl_cv_undef(pTHX_ CV *cv)
        }
        CvPADLIST(cv) = Nullav;
     }
+    else if (freecv)
+       SvREFCNT_dec(freecv);
     if (CvXSUB(cv)) {
         CvXSUB(cv) = 0;
     }
index 3c0a925..9c2b42f 100644 (file)
@@ -831,3 +831,16 @@ $人++; # a child is born
 print $人, "\n";
 EXPECT
 3
+########
+# test that closures generated by eval"" hold on to the CV of the eval""
+# for their entire lifetime
+$code = eval q[
+  sub { eval '$x = "ok 1\n"'; }
+];
+&{$code}();
+print $x;
+EXPECT
+ok 1
+######## [ID 20020623.009] nested eval/sub segfaults
+$eval = eval 'sub { eval "sub { %S }" }';
+$eval->({});