This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Fix two local *ISA bugs
[perl5.git] / scope.c
diff --git a/scope.c b/scope.c
index db2d43b..31b990d 100644 (file)
--- a/scope.c
+++ b/scope.c
@@ -160,8 +160,10 @@ Perl_free_tmps(pTHX)
     /* XXX should tmps_floor live in cxstack? */
     const I32 myfloor = PL_tmps_floor;
     while (PL_tmps_ix > myfloor) {      /* clean up after last statement */
-       SV* const sv = PL_tmps_stack[PL_tmps_ix];
-       PL_tmps_stack[PL_tmps_ix--] = NULL;
+       SV* const sv = PL_tmps_stack[PL_tmps_ix--];
+#ifdef PERL_POISON
+       PoisonWith(PL_tmps_stack + PL_tmps_ix + 1, 1, SV *, 0xAB);
+#endif
        if (sv && sv != &PL_sv_undef) {
            SvTEMP_off(sv);
            SvREFCNT_dec(sv);           /* note, can modify tmps_ix!!! */
@@ -283,22 +285,22 @@ Perl_save_gp(pTHX_ GV *gv, I32 empty)
 
     if (empty) {
        GP *gp = Perl_newGP(aTHX_ gv);
-
-       if (GvCVu(gv))
-            mro_method_changed_in(GvSTASH(gv)); /* taking a method out of circulation ("local")*/
+       HV * const stash = GvSTASH(gv);
+       bool isa_changed = 0;
+
+       if (stash && HvENAME(stash)) {
+           if (GvNAMELEN(gv) == 3 && strnEQ(GvNAME(gv), "ISA", 3))
+               isa_changed = TRUE;
+           else if (GvCVu(gv))
+               /* taking a method out of circulation ("local")*/
+                mro_method_changed_in(stash);
+       }
        if (GvIOp(gv) && (IoFLAGS(GvIOp(gv)) & IOf_ARGV)) {
            gp->gp_io = newIO();
            IoFLAGS(gp->gp_io) |= IOf_ARGV|IOf_START;
        }
-#ifdef PERL_DONT_CREATE_GVSV
-       if (gv == PL_errgv) {
-           /* We could scatter this logic everywhere by changing the
-              definition of ERRSV from GvSV() to GvSVn(), but it seems more
-              efficient to do this check once here.  */
-           gp->gp_sv = newSV(0);
-       }
-#endif
        GvGP_set(gv,gp);
+       if (isa_changed) mro_isa_changed_in(stash);
     }
     else {
        gp_ref(GvGP(gv));
@@ -346,7 +348,7 @@ Perl_save_hash(pTHX_ GV *gv)
 }
 
 void
-Perl_save_item(pTHX_ register SV *item)
+Perl_save_item(pTHX_ SV *item)
 {
     dVAR;
     SV * const sv = newSVsv(item);
@@ -520,13 +522,13 @@ Perl_save_clearsv(pTHX_ SV **svp)
     PERL_ARGS_ASSERT_SAVE_CLEARSV;
 
     ASSERT_CURPAD_ACTIVE("save_clearsv");
+    SvPADSTALE_off(*svp); /* mark lexical as active */
     if ((offset_shifted >> SAVE_TIGHT_SHIFT) != offset)
        Perl_croak(aTHX_ "panic: pad offset %"UVuf" out of range (%p-%p)",
                   offset, svp, PL_curpad);
 
     SSCHECK(1);
     SSPUSHUV(offset_shifted | SAVEt_CLEARSV);
-    SvPADSTALE_off(*svp); /* mark lexical as active */
 }
 
 void
@@ -625,9 +627,10 @@ Perl_save_aelem_flags(pTHX_ AV *av, I32 idx, SV **sptr, const U32 flags)
     SvGETMAGIC(*sptr);
     save_pushptri32ptr(SvREFCNT_inc_simple(av), idx, SvREFCNT_inc(*sptr),
                       SAVEt_AELEM);
-    /* if it gets reified later, the restore will have the wrong refcnt */
+    /* The array needs to hold a reference count on its new element, so it
+       must be AvREAL. */
     if (!AvREAL(av) && AvREIFY(av))
-       SvREFCNT_inc_void(*sptr);
+       av_reify(av);
     save_scalar_at(sptr, flags); /* XXX - FIXME - see #60360 */
     if (flags & SAVEf_KEEPOLDELEM)
        return;
@@ -711,7 +714,7 @@ Perl_leave_scope(pTHX_ I32 base)
     char* str;
     I32 i;
     /* Localise the effects of the TAINT_NOT inside the loop.  */
-    bool was = PL_tainted;
+    bool was = TAINT_get;
 
     if (base < -1)
        Perl_croak(aTHX_ "panic: corrupt saved stack index %ld", (long) base);
@@ -815,8 +818,8 @@ Perl_leave_scope(pTHX_ I32 base)
        case SAVEt_BOOL:                        /* bool reference */
            ptr = SSPOPPTR;
            *(bool*)ptr = cBOOL(uv >> 8);
-
-           if (ptr == &PL_tainted) {
+#if !NO_TAINT_SUPPORT
+           if (ptr == &(TAINT_get)) {
                /* If we don't update <was>, to reflect what was saved on the
                 * stack for PL_tainted, then we will overwrite this attempt to
                 * restore it when we exit this routine.  Note that this won't
@@ -824,6 +827,7 @@ Perl_leave_scope(pTHX_ I32 base)
                 * such as I32 */
                was = *(bool*)ptr;
            }
+#endif
            break;
        case SAVEt_I32_SMALL:
            ptr = SSPOPPTR;
@@ -863,9 +867,13 @@ Perl_leave_scope(pTHX_ I32 base)
            gv = MUTABLE_GV(SSPOPPTR);
            gp_free(gv);
            GvGP_set(gv, (GP*)ptr);
-            /* putting a method back into circulation ("local")*/
-           if (GvCVu(gv) && (hv=GvSTASH(gv)) && HvENAME_get(hv))
-                mro_method_changed_in(hv);
+           if ((hv=GvSTASH(gv)) && HvENAME_get(hv)) {
+             if (GvNAMELEN(gv) == 3 && strnEQ(GvNAME(gv), "ISA", 3))
+               mro_isa_changed_in(hv);
+             else if (GvCVu(gv))
+                /* putting a method back into circulation ("local")*/  
+                gv_method_changed(gv);
+           }
            SvREFCNT_dec(gv);
            break;
        case SAVEt_FREESV:
@@ -882,111 +890,108 @@ Perl_leave_scope(pTHX_ I32 base)
            break;
        case SAVEt_FREEOP:
            ptr = SSPOPPTR;
-           ASSERT_CURPAD_LEGAL("SAVEt_FREEOP"); /* XXX DAPM tmp */
+           ASSERT_CURPAD_LEGAL("SAVEt_FREEOP");
            op_free((OP*)ptr);
            break;
        case SAVEt_FREEPV:
            ptr = SSPOPPTR;
            Safefree(ptr);
            break;
-       case SAVEt_CLEARSV:
-           ptr = (void*)&PL_curpad[uv >> SAVE_TIGHT_SHIFT];
-           sv = *(SV**)ptr;
-
-           DEBUG_Xv(PerlIO_printf(Perl_debug_log,
-            "Pad 0x%"UVxf"[0x%"UVxf"] clearsv: %ld sv=0x%"UVxf"<%"IVdf"> %s\n",
-               PTR2UV(PL_comppad), PTR2UV(PL_curpad),
-               (long)((SV **)ptr-PL_curpad), PTR2UV(sv), (IV)SvREFCNT(sv),
-               (SvREFCNT(sv) <= 1 && !SvOBJECT(sv)) ? "clear" : "abandon"
-           ));
-
-           /* Can clear pad variable in place? */
-           if (SvREFCNT(sv) <= 1 && !SvOBJECT(sv)) {
-               /*
-                * if a my variable that was made readonly is going out of
-                * scope, we want to remove the readonlyness so that it can
-                * go out of scope quietly
-                */
-               if (SvPADMY(sv) && !SvFAKE(sv))
-                   SvREADONLY_off(sv);
-
-               if (SvTHINKFIRST(sv))
-                   sv_force_normal_flags(sv, SV_IMMEDIATE_UNREF
-                                            |SV_COW_DROP_PV);
-               if (SvTYPE(sv) == SVt_PVHV)
-                   Perl_hv_kill_backrefs(aTHX_ MUTABLE_HV(sv));
-               if (SvMAGICAL(sv))
-               {
-                 sv_unmagic(sv, PERL_MAGIC_backref);
-                 if (SvTYPE(sv) != SVt_PVCV)
-                   mg_free(sv);
-               }
 
-               switch (SvTYPE(sv)) {
-               case SVt_NULL:
-                   break;
-               case SVt_PVAV:
-                   av_clear(MUTABLE_AV(sv));
-                   break;
-               case SVt_PVHV:
-                   hv_clear(MUTABLE_HV(sv));
-                   break;
-               case SVt_PVCV:
-               {
-                   HEK * const hek = CvNAME_HEK((CV *)sv);
-                   assert(hek);
-                   share_hek_hek(hek);
-                   cv_undef((CV *)sv);
-                   CvNAME_HEK_set(sv, hek);
-                   break;
-               }
-               default:
-                   SvOK_off(sv);
-                   break;
-               }
-               SvPADSTALE_on(sv); /* mark as no longer live */
-           }
-           else {      /* Someone has a claim on this, so abandon it. */
-               assert(  SvFLAGS(sv) & SVs_PADMY);
-               assert(!(SvFLAGS(sv) & SVs_PADTMP));
-               switch (SvTYPE(sv)) {   /* Console ourselves with a new value */
-               case SVt_PVAV:  *(SV**)ptr = MUTABLE_SV(newAV());       break;
-               case SVt_PVHV:  *(SV**)ptr = MUTABLE_SV(newHV());       break;
-               case SVt_PVCV:
-               {
-                   SV ** const svp = (SV **)ptr;
-                   MAGIC *mg = SvMAGIC(sv);
-                   MAGIC **tomg = &SvMAGIC(sv);
-
-                   /* Create a stub */
-                   *svp = newSV_type(SVt_PVCV);
-
-                   /* Share name */
-                   assert(CvNAMED(sv));
-                   CvNAME_HEK_set(*svp,
-                       share_hek_hek(CvNAME_HEK((CV *)sv)));
-
-                   /* Steal magic */
-                   while (mg) {
-                       if (mg->mg_type == PERL_MAGIC_proto) break;
-                       mg = *(tomg = &mg->mg_moremagic);
-                   }
-                   assert(mg);
-                   *tomg = mg->mg_moremagic;
-                   mg->mg_moremagic = SvMAGIC(*svp);
-                   SvMAGIC(*svp) = mg;
-                   mg_magical(*svp);
-                   mg_magical(sv);
-                   break;
-               }
-               default:        *(SV**)ptr = newSV(0);          break;
-               }
-               SvREFCNT_dec(sv);       /* Cast current value to the winds. */
-               /* preserve pad nature, but also mark as not live
-                * for any closure capturing */
-               SvFLAGS(*(SV**)ptr) |= (SVs_PADMY|SVs_PADSTALE);
-           }
+        {
+          SV **svp;
+        case SAVEt_CLEARPADRANGE:
+            i = (I32)((uv >> SAVE_TIGHT_SHIFT) & OPpPADRANGE_COUNTMASK);
+           svp = &PL_curpad[uv >>
+                    (OPpPADRANGE_COUNTSHIFT + SAVE_TIGHT_SHIFT)] + i - 1;
+            goto clearsv;
+       case SAVEt_CLEARSV:
+           svp = &PL_curpad[uv >> SAVE_TIGHT_SHIFT];
+            i = 1;
+          clearsv:
+            for (; i; i--, svp--) {
+                sv = *svp;
+
+                DEBUG_Xv(PerlIO_printf(Perl_debug_log,
+             "Pad 0x%"UVxf"[0x%"UVxf"] clearsv: %ld sv=0x%"UVxf"<%"IVdf"> %s\n",
+                    PTR2UV(PL_comppad), PTR2UV(PL_curpad),
+                    (long)(svp-PL_curpad), PTR2UV(sv), (IV)SvREFCNT(sv),
+                    (SvREFCNT(sv) <= 1 && !SvOBJECT(sv)) ? "clear" : "abandon"
+                ));
+
+                /* Can clear pad variable in place? */
+                if (SvREFCNT(sv) <= 1 && !SvOBJECT(sv)) {
+                    /*
+                     * if a my variable that was made readonly is going out of
+                     * scope, we want to remove the readonlyness so that it can
+                     * go out of scope quietly
+                     */
+                    if (SvPADMY(sv) && !SvFAKE(sv))
+                        SvREADONLY_off(sv);
+
+                    if (SvTHINKFIRST(sv))
+                        sv_force_normal_flags(sv, SV_IMMEDIATE_UNREF
+                                                 |SV_COW_DROP_PV);
+                    if (SvTYPE(sv) == SVt_PVHV)
+                        Perl_hv_kill_backrefs(aTHX_ MUTABLE_HV(sv));
+                    if (SvMAGICAL(sv))
+                    {
+                      sv_unmagic(sv, PERL_MAGIC_backref);
+                      if (SvTYPE(sv) != SVt_PVCV)
+                        mg_free(sv);
+                    }
+
+                    switch (SvTYPE(sv)) {
+                    case SVt_NULL:
+                        break;
+                    case SVt_PVAV:
+                        av_clear(MUTABLE_AV(sv));
+                        break;
+                    case SVt_PVHV:
+                        hv_clear(MUTABLE_HV(sv));
+                        break;
+                    case SVt_PVCV:
+                    {
+                        HEK * const hek = CvNAME_HEK((CV *)sv);
+                        assert(hek);
+                        share_hek_hek(hek);
+                        cv_undef((CV *)sv);
+                        CvNAME_HEK_set(sv, hek);
+                        break;
+                    }
+                    default:
+                        SvOK_off(sv);
+                        break;
+                    }
+                    SvPADSTALE_on(sv); /* mark as no longer live */
+                }
+                else { /* Someone has a claim on this, so abandon it. */
+                    assert(  SvFLAGS(sv) & SVs_PADMY);
+                    assert(!(SvFLAGS(sv) & SVs_PADTMP));
+                    switch (SvTYPE(sv)) {      /* Console ourselves with a new value */
+                    case SVt_PVAV:     *svp = MUTABLE_SV(newAV());     break;
+                    case SVt_PVHV:     *svp = MUTABLE_SV(newHV());     break;
+                    case SVt_PVCV:
+                    {
+                        /* Create a stub */
+                        *svp = newSV_type(SVt_PVCV);
+
+                        /* Share name */
+                        assert(CvNAMED(sv));
+                        CvNAME_HEK_set(*svp,
+                            share_hek_hek(CvNAME_HEK((CV *)sv)));
+                        break;
+                    }
+                    default:   *svp = newSV(0);                break;
+                    }
+                    SvREFCNT_dec(sv);  /* Cast current value to the winds. */
+                    /* preserve pad nature, but also mark as not live
+                     * for any closure capturing */
+                    SvFLAGS(*svp) |= (SVs_PADMY|SVs_PADSTALE);
+                }
+            }
            break;
+        }
        case SAVEt_DELETE:
            ptr = SSPOPPTR;
            hv = MUTABLE_HV(ptr);
@@ -1189,7 +1194,7 @@ Perl_leave_scope(pTHX_ I32 base)
        }
     }
 
-    PL_tainted = was;
+    TAINT_set(was);
 
     PERL_ASYNC_CHECK();
 }
@@ -1204,6 +1209,7 @@ Perl_cx_dump(pTHX_ PERL_CONTEXT *cx)
 #ifdef DEBUGGING
     PerlIO_printf(Perl_debug_log, "CX %ld = %s\n", (long)(cx - cxstack), PL_block_type[CxTYPE(cx)]);
     if (CxTYPE(cx) != CXt_SUBST) {
+       const char *gimme_text;
        PerlIO_printf(Perl_debug_log, "BLK_OLDSP = %ld\n", (long)cx->blk_oldsp);
        PerlIO_printf(Perl_debug_log, "BLK_OLDCOP = 0x%"UVxf"\n",
                      PTR2UV(cx->blk_oldcop));
@@ -1211,7 +1217,21 @@ Perl_cx_dump(pTHX_ PERL_CONTEXT *cx)
        PerlIO_printf(Perl_debug_log, "BLK_OLDSCOPESP = %ld\n", (long)cx->blk_oldscopesp);
        PerlIO_printf(Perl_debug_log, "BLK_OLDPM = 0x%"UVxf"\n",
                      PTR2UV(cx->blk_oldpm));
-       PerlIO_printf(Perl_debug_log, "BLK_GIMME = %s\n", cx->blk_gimme ? "LIST" : "SCALAR");
+       switch (cx->blk_gimme) {
+           case G_VOID:
+               gimme_text = "VOID";
+               break;
+           case G_SCALAR:
+               gimme_text = "SCALAR";
+               break;
+           case G_ARRAY:
+               gimme_text = "LIST";
+               break;
+           default:
+               gimme_text = "UNKNOWN";
+               break;
+       }
+       PerlIO_printf(Perl_debug_log, "BLK_GIMME = %s\n", gimme_text);
     }
     switch (CxTYPE(cx)) {
     case CXt_NULL: