From 0df2568b7d017f31f412f393b443d798ed61602d Mon Sep 17 00:00:00 2001 From: Father Chrysostomos Date: Sat, 24 Dec 2011 23:35:52 -0800 Subject: [PATCH] select() can return undef when defoutgv is set If PL_defoutgv has been deleted from its stash, select() returns it as a ref, but if the stash has been freed (even though the gv still exists), it returns undef. That makes no sense. This is one of those nice cases where simplifying the code fixes a bug. --- pp_sys.c | 14 +++++--------- t/op/select.t | 9 ++++++++- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/pp_sys.c b/pp_sys.c index 661e0fc..a5fcb00 100644 --- a/pp_sys.c +++ b/pp_sys.c @@ -1224,24 +1224,20 @@ PP(pp_select) HV *hv; GV * const newdefout = (PL_op->op_private > 0) ? (MUTABLE_GV(POPs)) : NULL; GV * egv = GvEGVx(PL_defoutgv); + GV * const *gvp; if (!egv) egv = PL_defoutgv; hv = isGV_with_GP(egv) ? GvSTASH(egv) : NULL; - if (! hv) - XPUSHs(&PL_sv_undef); - else { - GV * const * const gvp = - HvENAME(hv) + gvp = hv && HvENAME(hv) ? (GV**)hv_fetch(hv, GvNAME(egv), HEK_UTF8(GvNAME_HEK(egv)) ? -GvNAMELEN(egv) : GvNAMELEN(egv), FALSE) : NULL; - if (gvp && *gvp == egv) { + if (gvp && *gvp == egv) { gv_efullname4(TARG, PL_defoutgv, NULL, TRUE); XPUSHTARG; - } - else { + } + else { mXPUSHs(newRV(MUTABLE_SV(egv))); - } } if (newdefout) { diff --git a/t/op/select.t b/t/op/select.t index 06caf1d..1994dd2 100644 --- a/t/op/select.t +++ b/t/op/select.t @@ -5,7 +5,7 @@ BEGIN { require './test.pl'; } -plan reverse 8; +plan reverse 9; open my $fh, "test.pl" or die "$0 unfortunately cannot open test.pl: $!"; @@ -25,3 +25,10 @@ $stash = \%foo::; *foo:: = *bar::; is select, $handle, 'select returns ref for glob whose stash has been detached'; + +open thwat::snin, "test.pl" or die "$0 is unable to open test.pl: $!"; +select thwat::snin; +$handle = \*thwat::snin; +*thwat:: = *snin::; # gv is now *__ANON__::snin +is select, $handle, + 'select returns ref for glob with no stash pointer'; -- 2.7.4