diff options
author | Father Chrysostomos <sprout@cpan.org> | 2010-09-26 11:09:28 -0700 |
---|---|---|
committer | Father Chrysostomos <sprout@cpan.org> | 2010-09-26 11:09:28 -0700 |
commit | 13be902cef8b01c085a6b8b1b59fa2754a10cdfb (patch) | |
tree | 36349eb3f2bffa12f01cf0fa38a37036a8b80448 /sv.c | |
parent | 25e68b8bdd34f742e9a4780090bafa60c943ec14 (diff) | |
download | perl-13be902cef8b01c085a6b8b1b59fa2754a10cdfb.tar.gz |
[perl #77362] Assigning glob to lvalue causes stringification
This test from t/op/gv.t was added by change 22315/4ce457a6:
{
# test the assignment of a GLOB to an LVALUE
my $e = '';
local $SIG{__DIE__} = sub { $e = $_[0] };
my $v;
sub f { $_[0] = 0; $_[0] = "a"; $_[0] = *DATA }
f($v);
is ($v, '*main::DATA');
my $x = <$v>;
is ($x, "perl\n");
}
That change was the one that made glob-to-lvalue assignment work to
begin with. But this test passes in perl version *prior* to that
change.
This patch fixes the test and adds tests to make sure what is assigned
is actually a glob, and not just a string.
It also happens to fix the stringification bug. In doing so, it essen-
tially ‘enables’ globs-as-PVLVs.
It turns out that many different parts of the perl source don’t fully
take this into account, so this patch also fixes the following to work
with them (I tried to make these into separate patches, but they are
so intertwined it just got too complicated):
• GvIO(gv) to make readline and other I/O ops work.
• Autovivification of glob slots.
• tie *$pvlv
• *$pvlv = undef, *$pvlv = $number, *$pvlv = $ref
• Duplicating a filehandle accessed through a PVLV glob when the
stringified form of the glob cannot be used to access the file
handle (!)
• Using a PVLV glob as a subroutine reference
• Coderef assignment when the glob is no longer in the symbol table
• open with a PVLV glob for the filehandle
• -t and -T
• Unopened file handle warnings
Diffstat (limited to 'sv.c')
-rw-r--r-- | sv.c | 41 |
1 files changed, 23 insertions, 18 deletions
@@ -3806,7 +3806,7 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV* sstr, const I32 flags) switch (stype) { case SVt_NULL: undef_sstr: - if (dtype != SVt_PVGV) { + if (dtype != SVt_PVGV && dtype != SVt_PVLV) { (void)SvOK_off(dstr); return; } @@ -3822,6 +3822,7 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV* sstr, const I32 flags) sv_upgrade(dstr, SVt_PVIV); break; case SVt_PVGV: + case SVt_PVLV: goto end_of_first_switch; } (void)SvIOK_only(dstr); @@ -3853,6 +3854,7 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV* sstr, const I32 flags) sv_upgrade(dstr, SVt_PVNV); break; case SVt_PVGV: + case SVt_PVLV: goto end_of_first_switch; } SvNV_set(dstr, SvNVX(sstr)); @@ -3905,7 +3907,7 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV* sstr, const I32 flags) /* case SVt_BIND: */ case SVt_PVLV: case SVt_PVGV: - if (isGV_with_GP(sstr) && dtype <= SVt_PVGV) { + if (isGV_with_GP(sstr) && dtype <= SVt_PVLV) { glob_assign_glob(dstr, sstr, dtype); return; } @@ -3915,12 +3917,11 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV* sstr, const I32 flags) case SVt_PVMG: if (SvGMAGICAL(sstr) && (flags & SV_GMAGIC)) { mg_get(sstr); - if (SvTYPE(sstr) != stype) { + if (SvTYPE(sstr) != stype) stype = SvTYPE(sstr); - if (isGV_with_GP(sstr) && stype == SVt_PVGV && dtype <= SVt_PVGV) { + if (isGV_with_GP(sstr) && dtype <= SVt_PVLV) { glob_assign_glob(dstr, sstr, dtype); return; - } } } if (stype == SVt_PVLV) @@ -3955,7 +3956,7 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV* sstr, const I32 flags) else Perl_croak(aTHX_ "Cannot copy to %s", type); } else if (sflags & SVf_ROK) { - if (isGV_with_GP(dstr) && dtype == SVt_PVGV + if (isGV_with_GP(dstr) && SvTYPE(SvRV(sstr)) == SVt_PVGV && isGV_with_GP(SvRV(sstr))) { sstr = SvRV(sstr); if (sstr == dstr) { @@ -3972,7 +3973,7 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV* sstr, const I32 flags) } if (dtype >= SVt_PV) { - if (dtype == SVt_PVGV && isGV_with_GP(dstr)) { + if (isGV_with_GP(dstr)) { glob_assign_ref(dstr, sstr); return; } @@ -3990,7 +3991,7 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV* sstr, const I32 flags) assert(!(sflags & SVf_NOK)); assert(!(sflags & SVf_IOK)); } - else if (dtype == SVt_PVGV && isGV_with_GP(dstr)) { + else if (isGV_with_GP(dstr)) { if (!(sflags & SVf_OK)) { Perl_ck_warner(aTHX_ packWARN(WARN_MISC), "Undefined value assigned to typeglob"); @@ -4591,7 +4592,7 @@ Perl_sv_force_normal_flags(pTHX_ register SV *const sv, const U32 flags) #endif if (SvROK(sv)) sv_unref_flags(sv, flags); - else if (SvFAKE(sv) && SvTYPE(sv) == SVt_PVGV) + else if (SvFAKE(sv) && isGV_with_GP(sv)) sv_unglob(sv); else if (SvFAKE(sv) && SvTYPE(sv) == SVt_REGEXP) { /* Need to downgrade the REGEXP to a simple(r) scalar. This is analagous @@ -8444,6 +8445,7 @@ Perl_sv_2io(pTHX_ SV *const sv) io = MUTABLE_IO(sv); break; case SVt_PVGV: + case SVt_PVLV: if (isGV_with_GP(sv)) { gv = MUTABLE_GV(sv); io = GvIO(gv); @@ -9047,7 +9049,8 @@ Perl_sv_bless(pTHX_ SV *const sv, HV *const stash) return sv; } -/* Downgrades a PVGV to a PVMG. +/* Downgrades a PVGV to a PVMG. If it’s actually a PVLV, we leave the type + * as it is after unglobbing it. */ STATIC void @@ -9060,7 +9063,7 @@ S_sv_unglob(pTHX_ SV *const sv) PERL_ARGS_ASSERT_SV_UNGLOB; - assert(SvTYPE(sv) == SVt_PVGV); + assert(SvTYPE(sv) == SVt_PVGV || SvTYPE(sv) == SVt_PVLV); SvFAKE_off(sv); gv_efullname3(temp, MUTABLE_GV(sv), "*"); @@ -9080,14 +9083,16 @@ S_sv_unglob(pTHX_ SV *const sv) } isGV_with_GP_off(sv); - /* need to keep SvANY(sv) in the right arena */ - xpvmg = new_XPVMG(); - StructCopy(SvANY(sv), xpvmg, XPVMG); - del_XPVGV(SvANY(sv)); - SvANY(sv) = xpvmg; + if(SvTYPE(sv) == SVt_PVGV) { + /* need to keep SvANY(sv) in the right arena */ + xpvmg = new_XPVMG(); + StructCopy(SvANY(sv), xpvmg, XPVMG); + del_XPVGV(SvANY(sv)); + SvANY(sv) = xpvmg; - SvFLAGS(sv) &= ~SVTYPEMASK; - SvFLAGS(sv) |= SVt_PVMG; + SvFLAGS(sv) &= ~SVTYPEMASK; + SvFLAGS(sv) |= SVt_PVMG; + } /* Intentionally not calling any local SET magic, as this isn't so much a set operation as merely an internal storage change. */ |