fix for [perl #65582] anon globs segfaulting
David Mitchell [Tue, 12 Jan 2010 00:14:41 +0000 (00:14 +0000)]
The following code has had differing behaviours:

    my $io_ref = *STDOUT{IO};
    my $glob = *$io_ref;

          defined($glob)    "$glob"
          --------------    -------
5.8.8       false           "" with uninit warning
5.10.0      true            (coredump)
this commit true            ""

$glob is essentially an anonymous typeglob (no NAME, EGV or GvSTASH).
It shouldn't register as undefined since it's clearly a valid GV with a
valid IO slot; Stringifying to "" seems to be the right thing, and not
warning seems right too, since its not undef.

sv.c
t/op/gv.t

diff --git a/sv.c b/sv.c
index 063dd19..4e80e18 100644 (file)
--- a/sv.c
+++ b/sv.c
@@ -2986,11 +2986,17 @@ Perl_sv_2pv_flags(pTHX_ register SV *const sv, STRLEN *const lp, const I32 flags
            gv_efullname3(buffer, gv, "*");
            SvFLAGS(gv) |= wasfake;
 
-           assert(SvPOK(buffer));
-           if (lp) {
-               *lp = SvCUR(buffer);
+           if (SvPOK(buffer)) {
+               if (lp) {
+                   *lp = SvCUR(buffer);
+               }
+               return SvPVX(buffer);
+           }
+           else {
+               if (lp)
+                   *lp = 0;
+               return (char *)"";
            }
-           return SvPVX(buffer);
        }
 
        if (lp)
index 1b705ef..72787c4 100644 (file)
--- a/t/op/gv.t
+++ b/t/op/gv.t
@@ -12,7 +12,7 @@ BEGIN {
 use warnings;
 
 require './test.pl';
-plan( tests => 178 );
+plan( tests => 181 );
 
 # type coersion on assignment
 $foo = 'foo';
@@ -560,6 +560,27 @@ foreach my $type (qw(integer number string)) {
          "with the correct error message");
 }
 
+# RT #60954 anonymous glob should be defined, and not coredump when
+# stringified. The behaviours are:
+#
+#        defined($glob)    "$glob"
+# 5.8.8     false           "" with uninit warning
+# 5.10.0    true            (coredump)
+# 5.12.0    true            ""
+
+{
+    my $io_ref = *STDOUT{IO};
+    my $glob = *$io_ref;
+    ok(defined $glob, "RT #60954 anon glob should be defined");
+
+    my $warn = '';
+    local $SIG{__WARN__} = sub { $warn = $_[0] };
+    use warnings;
+    my $str = "$glob";
+    is($warn, '', "RT #60954 anon glob stringification shouln't warn");
+    is($str,  '', "RT #60954 anon glob stringification should be empty");
+}
+
 __END__
 Perl
 Rules