This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
In S_doparseform(), don't force the pattern to a string. This resolves #79532
[perl5.git] / mg.c
diff --git a/mg.c b/mg.c
index 331e34b..54791cb 100644 (file)
--- a/mg.c
+++ b/mg.c
@@ -84,6 +84,7 @@ struct magic_state {
     I32 mgs_ss_ix;
     U32 mgs_magical;
     bool mgs_readonly;
+    bool mgs_bumped;
 };
 /* MGS is typedef'ed to struct magic_state in perl.h */
 
@@ -92,12 +93,20 @@ S_save_magic(pTHX_ I32 mgs_ix, SV *sv)
 {
     dVAR;
     MGS* mgs;
+    bool bumped = FALSE;
 
     PERL_ARGS_ASSERT_SAVE_MAGIC;
 
-    /* guard against sv having being freed midway by holding a private
-       reference. */
-    SvREFCNT_inc_simple_void_NN(sv);
+    /* we shouldn't really be called here with RC==0, but it can sometimes
+     * happen via mg_clear() (which also shouldn't be called when RC==0,
+     * but it can happen). Handle this case gracefully(ish) by not RC++
+     * and thus avoiding the resultant double free */
+    if (SvREFCNT(sv) > 0) {
+    /* guard against sv getting freed midway through the mg clearing,
+     * by holding a private reference for the duration. */
+       SvREFCNT_inc_simple_void_NN(sv);
+       bumped = TRUE;
+    }
 
     assert(SvMAGICAL(sv));
     /* Turning READONLY off for a copy-on-write scalar (including shared
@@ -112,6 +121,7 @@ S_save_magic(pTHX_ I32 mgs_ix, SV *sv)
     mgs->mgs_magical = SvMAGICAL(sv);
     mgs->mgs_readonly = SvREADONLY(sv) != 0;
     mgs->mgs_ss_ix = PL_savestack_ix;   /* points after the saved destructor */
+    mgs->mgs_bumped = bumped;
 
     SvMAGICAL_off(sv);
     SvREADONLY_off(sv);
@@ -286,7 +296,7 @@ Perl_mg_set(pTHX_ SV *sv)
            mg->mg_flags &= ~MGf_GSKIP; /* setting requires another read */
            (SSPTR(mgs_ix, MGS*))->mgs_magical = 0;
        }
-       if (PL_localizing == 2 && !S_is_container_magic(mg))
+       if (PL_localizing == 2 && (!S_is_container_magic(mg) || sv == DEFSV))
            continue;
        if (vtbl && vtbl->svt_set)
            vtbl->svt_set(aTHX_ sv, mg);
@@ -511,6 +521,9 @@ Perl_mg_localize(pTHX_ SV *sv, SV *nsv, bool setmagic)
 
     PERL_ARGS_ASSERT_MG_LOCALIZE;
 
+    if (nsv == DEFSV)
+       return;
+
     for (mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) {
        const MGVTBL* const vtbl = mg->mg_virtual;
        if (!S_is_container_magic(mg))
@@ -2402,7 +2415,6 @@ Perl_magic_setregexp(pTHX_ SV *sv, MAGIC *mg)
        SvVALID_off(sv);
     } else {
        assert(type == PERL_MAGIC_fm);
-       SvCOMPILED_off(sv);
     }
     return sv_unmagic(sv, type);
 }
@@ -3144,6 +3156,7 @@ S_restore_magic(pTHX_ const void *p)
     dVAR;
     MGS* const mgs = SSPTR(PTR2IV(p), MGS*);
     SV* const sv = mgs->mgs_sv;
+    bool bumped;
 
     if (!sv)
         return;
@@ -3175,6 +3188,7 @@ S_restore_magic(pTHX_ const void *p)
        }
     }
 
+    bumped = mgs->mgs_bumped;
     mgs->mgs_sv = NULL;  /* mark the MGS structure as restored */
 
     /* If we're still on top of the stack, pop us off.  (That condition
@@ -3193,21 +3207,23 @@ S_restore_magic(pTHX_ const void *p)
         assert((popval & SAVE_MASK) == SAVEt_ALLOC);
         PL_savestack_ix -= popval >> SAVE_TIGHT_SHIFT;
     }
-    if (SvREFCNT(sv) == 1) {
-       /* We hold the last reference to this SV, which implies that the
-          SV was deleted as a side effect of the routines we called.
-          So artificially keep it alive a bit longer.
-          We avoid turning on the TEMP flag, which can cause the SV's
-          buffer to get stolen (and maybe other stuff). */
-       int was_temp = SvTEMP(sv);
-       sv_2mortal(sv);
-       if (!was_temp) {
-           SvTEMP_off(sv);
+    if (bumped) {
+       if (SvREFCNT(sv) == 1) {
+           /* We hold the last reference to this SV, which implies that the
+              SV was deleted as a side effect of the routines we called.
+              So artificially keep it alive a bit longer.
+              We avoid turning on the TEMP flag, which can cause the SV's
+              buffer to get stolen (and maybe other stuff). */
+           int was_temp = SvTEMP(sv);
+           sv_2mortal(sv);
+           if (!was_temp) {
+               SvTEMP_off(sv);
+           }
+           SvOK_off(sv);
        }
-       SvOK_off(sv);
+       else
+           SvREFCNT_dec(sv); /* undo the inc in S_save_magic() */
     }
-    else
-       SvREFCNT_dec(sv); /* undo the inc in S_save_magic() */
 }
 
 /* clean up the mess created by Perl_sighandler().