Remove ‘Can't coerce readonly %s’ error
authorFather Chrysostomos <sprout@cpan.org>
Sun, 23 Jun 2013 00:40:04 +0000 (17:40 -0700)
committerFather Chrysostomos <sprout@cpan.org>
Sun, 23 Jun 2013 06:16:41 +0000 (23:16 -0700)
$ ./perl -Ilib -e 'for(\1){ vec($_,0,1)=1 }'
Can't coerce readonly REF to string in sassign at -e line 1.

Why not ‘Modification of a read-only value’ as elsewhere?

The code in question, in sv_pvn_force_flags, allows references to
bypass the initial read-only check.  (This has been the case since
perl-5.005_02-1047-g6fc9266.  I think it was a mistake.)  Then there
is a check further down that croaks with this error, unless called as
SvPV_force_mutable (i.e., with the SV_MUTABLE_RETURN flag).

So that means read-only references can silently be flattened, regard-
less of the read-only flag, if the caller uses SvPV_force_mutable.
Fortunately, the only use of that macro in the core is in fbm_compile,
which I recently modified so that it wouldn’t touch references at all.

I don’t understand the logic that allows read-only thingies to be mod-
ified in the presence of the SV_MUTABLE_RETURN flag, but not other-
wise.  As of the previous commit, which removed the exception for
read-only scalars at compile time, nothing can reach that code except
read-only references.

This commit restores the logic inadvertently changed by 6fc9266 and
removes the code that becomes unreachable as a result.

sv.c
t/op/vec.t
t/porting/diag.t

diff --git a/sv.c b/sv.c
index 1b8d45b..81db766 100644 (file)
--- a/sv.c
+++ b/sv.c
@@ -9314,7 +9314,7 @@ Perl_sv_pvn_force_flags(pTHX_ SV *const sv, STRLEN *const lp, const I32 flags)
     PERL_ARGS_ASSERT_SV_PVN_FORCE_FLAGS;
 
     if (flags & SV_GMAGIC) SvGETMAGIC(sv);
-    if (SvTHINKFIRST(sv) && !SvROK(sv))
+    if (SvTHINKFIRST(sv) && (!SvROK(sv) || SvREADONLY(sv)))
         sv_force_normal_flags(sv, 0);
 
     if (SvPOK(sv)) {
@@ -9325,14 +9325,6 @@ Perl_sv_pvn_force_flags(pTHX_ SV *const sv, STRLEN *const lp, const I32 flags)
        char *s;
        STRLEN len;
  
-       if (SvREADONLY(sv) && !(flags & SV_MUTABLE_RETURN)) {
-           const char * const ref = sv_reftype(sv,0);
-           if (PL_op)
-               Perl_croak(aTHX_ "Can't coerce readonly %s to string in %s",
-                          ref, OP_DESC(PL_op));
-           else
-               Perl_croak(aTHX_ "Can't coerce readonly %s to string", ref);
-       }
        if (SvTYPE(sv) > SVt_PVLV
            || isGV_with_GP(sv))
            /* diag_listed_as: Can't coerce %s to %s in %s */
index 9e69c22..1743c18 100644 (file)
@@ -6,7 +6,7 @@ BEGIN {
 }
 
 require "test.pl";
-plan( tests => 32 );
+plan( tests => 33 );
 
 my $Is_EBCDIC = (ord('A') == 193) ? 1 : 0;
 
@@ -107,3 +107,7 @@ $destroyed = 0;
     $x = bless({}, 'Class');
 }
 is($destroyed, 1, 'Timely scalar destruction with lvalue vec');
+
+eval { for (\1) { vec($_,0,1) = 1 } };
+like($@, qr/^Modification of a read-only value attempted at /,
+        'err msg when modifying read-only refs');
index e21b102..91b5385 100644 (file)
@@ -459,8 +459,6 @@ __DATA__
 Malformed UTF-8 character (unexpected non-continuation byte 0x%x, immediately after start byte 0x%x)
 
 Cannot apply "%s" in non-PerlIO perl
-Can't coerce readonly %s to string
-Can't coerce readonly %s to string in %s
 Can't find string terminator %c%s%c anywhere before EOF
 Can't fix broken locale name "%s"
 Can't get short module name from a handle