When localising a magic value, propagate the readonly flag
Rafael Garcia-Suarez [Mon, 22 Sep 2003 20:31:19 +0000 (20:31 +0000)]
only if this scalar has \0 magic or has magic without a
'set' method. (follows change #20479 for bug #23141.)
p4raw-link: @20479 on //depot/perl: 33f3c7b8444b48791ad016570a41a23483d750d2

p4raw-id: //depot/perl@21323

scope.c
t/op/local.t

diff --git a/scope.c b/scope.c
index 33d891e..2c2ce36 100644 (file)
--- a/scope.c
+++ b/scope.c
@@ -199,9 +199,9 @@ S_save_scalar_at(pTHX_ SV **sptr)
 
     sv = *sptr = NEWSV(0,0);
     if (SvTYPE(osv) >= SVt_PVMG && SvMAGIC(osv) && SvTYPE(osv) != SVt_PVGV) {
+       MAGIC *mg;
        sv_upgrade(sv, SvTYPE(osv));
        if (SvGMAGICAL(osv)) {
-           MAGIC* mg;
            bool oldtainted = PL_tainted;
            mg_get(osv);                /* note, can croak! */
            if (PL_tainting && PL_tainted &&
@@ -214,7 +214,17 @@ S_save_scalar_at(pTHX_ SV **sptr)
            PL_tainted = oldtainted;
        }
        SvMAGIC(sv) = SvMAGIC(osv);
-       SvFLAGS(sv) |= SvMAGICAL(osv) | SvREADONLY(osv);
+       /* if it's a special scalar or if it has no 'set' magic,
+        * propagate the SvREADONLY flag. --rgs 20030922 */
+       for (mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) {
+           if (SvMAGIC(sv)->mg_type == '\0'
+                   || !SvMAGIC(sv)->mg_virtual->svt_set)
+           {
+               SvFLAGS(sv) |= SvREADONLY(osv);
+               break;
+           }
+       }
+       SvFLAGS(sv) |= SvMAGICAL(osv);
        /* XXX SvMAGIC() is *shared* between osv and sv.  This can
         * lead to coredumps when both SVs are destroyed without one
         * of their SvMAGIC() slots being NULLed. */
index 5a5b7ee..28613e7 100755 (executable)
@@ -1,6 +1,6 @@
 #!./perl
 
-print "1..78\n";
+print "1..79\n";
 
 sub foo {
     local($a, $b) = @_;
@@ -271,3 +271,8 @@ print "ok 77\n";
 eval { for ($1) { local $_ = 1 } };
 print "not " if $@;
 print "ok 78\n";
+
+# The s/// adds 'g' magic to $_, but it should remain non-readonly
+eval { for("a") { for $x (1,2) { local $_="b"; s/(.*)/+$1/ } } };
+print "not " if $@;
+print "ok 79\n";