This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
[perl #87388] bless[], "main::" crashes
authorFather Chrysostomos <sprout@cpan.org>
Thu, 7 Apr 2011 05:44:28 +0000 (22:44 -0700)
committerFather Chrysostomos <sprout@cpan.org>
Thu, 7 Apr 2011 05:44:28 +0000 (22:44 -0700)
commit1a063a891daa888a733d9623fd6d707de87c6bd9
tree0f388ab5059d7d3ea6f1a49d08ca1f7209f00866
parent837c87981b0d72533fc9e43f83cca13e78853569
[perl #87388] bless[], "main::" crashes

As mention in the ticket, this was caused by b4dd662, which removed
‘dead’ code from gv_stashpvn:

commit b4dd66232df8f0d1c00796970dec7fc37fbe9edf
Author: Nicholas Clark <nick@ccl4.org>
Date:   Fri Oct 8 21:33:29 2010 +0100

    Remove dead code from Perl_gv_stashpvn().

    GvHV() and HvNAME() will both always already be set, as gv_fetchpvn_flags()
    will initialise these as it walks the string in its initial loop to locate the
    correct stash, then return early because name == name_end.

    This code has been dead since it was added in 5.000.

--- a/gv.c
+++ b/gv.c
@@ -927,11 +927,9 @@ Perl_gv_stashpvn(pTHX_ const char *name, U32 namelen, I32 flags)
  Safefree(tmpbuf);
     if (!tmpgv)
  return NULL;
-    if (!GvHV(tmpgv))
- GvHV(tmpgv) = newHV();
     stash = GvHV(tmpgv);
-    if (!HvNAME_get(stash))
- hv_name_set(stash, name, namelen, 0);
+    assert(stash);
+    assert(HvNAME_get(stash));
     return stash;
 }

This routine, before the snippet shown, adds two colons to the end of
the name and then passes "main::::" to gv_fetch_pvn_flags.

gv_fetch_pvn_flags, when it parses a "::", sets the next subname to
point to the character after the second colon, and then continues
scanning from the next character *after* that. So foo::::bar becomes
$foo::{"::bar"} and main:::: becomes $main::{"::"}.

The code that assigns the name to the stash and the early exit are
both inside an if(we have a package separator) block, but the final ::
is not considered one, so a nameless hash is returned.

The easiest way to fix this is to revert just the changes to
lines that deal with the name (since the other deleted lines are
really dead).
gv.c
t/op/bless.t