From 552908b17471877454d99aa32f7ac5c29ea2efbb Mon Sep 17 00:00:00 2001 From: David Mitchell Date: Thu, 17 Oct 2013 15:35:14 +0100 Subject: [PATCH] PerlIO::scalar: stringify refs If $s in open my $fh, "<", \$s or similar is a ref, then stringify that ref: i.e. convert it from a ref into the string "SCALAR(0x....)" or whatever. This fixes RT #119529 Filehandle opened from ref to ref hangs on reading which in this case was looping forever, since it kept thinking that the var was a string ("SCALAR.."), but whose length was 0. I haven't gone for a complete "always force var into a string" approach, since PerlIO::scalar has quite a tolerance for "bad" vars; e.g. it won't warn if $var is undef or a read-only constant number etc; and it already normalises under some circumstances and not others. So I've just increased the cases somewhat where it normalises. Also, I didn't look to closely at the code that was looping (or to put it another way, I looked at it but didn't understand it), so it could conceivably still behave badly on some other strange type of variable that manages to avoid getting normalised. --- ext/PerlIO-scalar/scalar.pm | 2 +- ext/PerlIO-scalar/scalar.xs | 7 ++++++- ext/PerlIO-scalar/t/scalar.t | 11 ++++++++++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/ext/PerlIO-scalar/scalar.pm b/ext/PerlIO-scalar/scalar.pm index 64ecc22..e38dd54 100644 --- a/ext/PerlIO-scalar/scalar.pm +++ b/ext/PerlIO-scalar/scalar.pm @@ -1,5 +1,5 @@ package PerlIO::scalar; -our $VERSION = '0.16'; +our $VERSION = '0.17'; require XSLoader; XSLoader::load(); 1; diff --git a/ext/PerlIO-scalar/scalar.xs b/ext/PerlIO-scalar/scalar.xs index e7e8330..95668e7 100644 --- a/ext/PerlIO-scalar/scalar.xs +++ b/ext/PerlIO-scalar/scalar.xs @@ -48,7 +48,12 @@ PerlIOScalar_pushed(pTHX_ PerlIO * f, const char *mode, SV * arg, else { s->var = newSVpvn("", 0); } - SvUPGRADE(s->var, SVt_PV); + if (SvROK(s->var)) + /* force refs, overload etc to be plain strings */ + (void)SvPV_force_nomg_nolen(s->var); + else + SvUPGRADE(s->var, SVt_PV); + code = PerlIOBase_pushed(aTHX_ f, mode, Nullsv, tab); if (!SvOK(s->var) || (PerlIOBase(f)->flags) & PERLIO_F_TRUNCATE) { diff --git a/ext/PerlIO-scalar/t/scalar.t b/ext/PerlIO-scalar/t/scalar.t index 5a91071..f5ee47e 100644 --- a/ext/PerlIO-scalar/t/scalar.t +++ b/ext/PerlIO-scalar/t/scalar.t @@ -16,7 +16,7 @@ use Fcntl qw(SEEK_SET SEEK_CUR SEEK_END); # Not 0, 1, 2 everywhere. $| = 1; -use Test::More tests => 108; +use Test::More tests => 109; my $fh; my $var = "aaa\n"; @@ -462,3 +462,12 @@ my $byte_warning = "Strings with code points over 0xFF may not be mapped into in ok(!(print $fh "B"), "write to an non-downgradable SV (and warn)"); is_deeply(\@warnings, [ $byte_warning ], "check warning"); } + +# RT #119529: non-string should be forced into a string + +{ + my $x = \42; + open my $fh, "<", \$x; + my $got = <$fh>; # this used to loop + like($got, qr/^SCALAR\(0x[0-9a-f]+\)$/, "ref to a ref"); +} -- 2.7.4