This has the side-effect of fixing these one-liners:
$ perl5.13.5 -le' my $glob = \*foo::ISA; delete $::{"foo::"}; *$glob = *a'
Bus error
$ perl5.13.5 -le' my $glob = \*foo::ISA; delete $::{"foo::"}; *$glob = []'
Bus error
$ perl5.13.6 -le'sub baz; my $glob = \*foo::bar; delete $::{"foo::"}; *$glob = *baz;'
Bus error
$ perl5.13.6 -le'sub foo::bar; my $glob = \*foo::bar; delete $::{"foo::"}; *$glob = *baz;'
Bus error
In the first two cases the crash was inadvertently fixed (isn’t it
nice when that happens?) in 5.13.6 (by
6f86b615fa7), but there was
still a fatal error:
Can't call mro_isa_changed_in() on anonymous symbol table at -e line 1.
Because sv_clear calls ->DESTROY, if an object’s stash has been
detached from the symbol table, mro_get_linear_isa can be called on a
hash with no HvENAME. So HvNAME is used as a fallback for those cases.
if (!entry)
return;
val = HeVAL(entry);
- if (val && isGV(val) && isGV_with_GP(val) && GvCVu(val) && HvNAME_get(hv))
+ if (val && isGV(val) && isGV_with_GP(val) && GvCVu(val) && HvENAME(hv))
mro_method_changed_in(hv); /* deletion of method from stash */
SvREFCNT_dec(val);
if (HeKLEN(entry) == HEf_SVKEY) {
HvREHASH_off(hv);
reset:
if (SvOOK(hv)) {
- if(HvNAME_get(hv))
+ if(HvENAME_get(hv))
mro_isa_changed_in(hv);
HvEITER_set(hv, NULL);
}
DEBUG_A(Perl_hv_assert(aTHX_ hv));
xhv = (XPVHV*)SvANY(hv);
- if ((name = HvNAME_get(hv)) && !PL_dirty)
+ if ((name = HvENAME_get(hv)) && !PL_dirty)
mro_isa_changed_in(hv);
hfreeentries(hv);
- if (name) {
+ if (name || (name = HvNAME(hv))) {
if (PL_stashcache)
(void)hv_delete(PL_stashcache, name, HvNAMELEN_get(hv), G_DISCARD);
hv_name_set(hv, NULL, 0, 0);
: (const GV *)mg_find(mg->mg_obj, PERL_MAGIC_isa)->mg_obj
);
- if (stash)
+ /* The stash may have been detached from the symbol table, so check its
+ name before doing anything. */
+ if (stash && HvENAME_get(stash))
mro_isa_changed_in(stash);
return 0;
PERL_ARGS_ASSERT_MRO_GET_LINEAR_ISA_DFS;
assert(HvAUX(stash));
- stashhek = HvNAME_HEK(stash);
+ stashhek
+ = HvAUX(stash)->xhv_name && HvENAME_HEK_NN(stash)
+ ? HvENAME_HEK_NN(stash)
+ : HvNAME_HEK(stash);
+
if (!stashhek)
Perl_croak(aTHX_ "Can't linearize anonymous symbol table");
struct mro_meta * meta = NULL;
if(!stashname && stash) {
- stashname = HvNAME_get(stash);
- stashname_len = HvNAMELEN_get(stash);
+ stashname = HvENAME_get(stash);
+ stashname_len = HvENAMELEN_get(stash);
}
else if(!stash)
stash = gv_stashpvn(stashname, stashname_len, 0 /* don't add */);
stashentry && *stashentry
&& (substash = GvHV(*stashentry))
)
- || (oldsubstash && HvNAME(oldsubstash))
+ || (oldsubstash && HvENAME_get(oldsubstash))
)
{
/* Add :: and the key (minus the trailing ::)
}
set_names:
- if(oldstash && HvNAME(oldstash)) {
+ if(oldstash && HvENAME_get(oldstash)) {
if(PL_stashcache)
(void)
hv_delete(PL_stashcache, newname, newname_len, G_DISCARD);
void
Perl_mro_method_changed_in(pTHX_ HV *stash)
{
- const char * const stashname = HvNAME_get(stash);
- const STRLEN stashname_len = HvNAMELEN_get(stash);
+ const char * const stashname = HvENAME_get(stash);
+ const STRLEN stashname_len = HvENAMELEN_get(stash);
SV ** const svp = hv_fetch(PL_isarev, stashname, stashname_len, 0);
HV * const isarev = svp ? MUTABLE_HV(*svp) : NULL;
HV *stash;
/* undef *Foo:: */
- if((stash = GvHV((const GV *)sv)) && HvNAME_get(stash))
+ if((stash = GvHV((const GV *)sv)) && HvENAME_get(stash))
mro_isa_changed_in(stash);
/* undef *Pkg::meth_name ... */
else if(GvCVu((const GV *)sv) && (stash = GvSTASH((const GV *)sv))
- && HvNAME_get(stash))
+ && HvENAME_get(stash))
mro_method_changed_in(stash);
gp_free(MUTABLE_GV(sv));
if (SSPOPINT)
SvFAKE_on(gv);
/* putting a method back into circulation ("local")*/
- if (GvCVu(gv) && (hv=GvSTASH(gv)) && HvNAME_get(hv))
+ if (GvCVu(gv) && (hv=GvSTASH(gv)) && HvENAME_get(hv))
mro_method_changed_in(hv);
SvREFCNT_dec(gv);
break;
}
/* If source has a real method, then a method is
going to change */
- else if(GvCV((const GV *)sstr)) {
+ else if(
+ GvCV((const GV *)sstr) && GvSTASH(dstr) && HvENAME(GvSTASH(dstr))
+ ) {
mro_changes = 1;
}
}
/* If dest already had a real method, that's a change as well */
- if(!mro_changes && GvGP(MUTABLE_GV(dstr)) && GvCVu((const GV *)dstr)) {
+ if(
+ !mro_changes && GvGP(MUTABLE_GV(dstr)) && GvCVu((const GV *)dstr)
+ && GvSTASH(dstr) && HvENAME(GvSTASH(dstr))
+ ) {
mro_changes = 1;
}
glob to begin with. */
if(dtype == SVt_PVGV) {
const char * const name = GvNAME((const GV *)dstr);
- if(strEQ(name,"ISA"))
+ if(
+ strEQ(name,"ISA")
+ /* The stash may have been detached from the symbol table, so
+ check its name. */
+ && GvSTASH(dstr) && HvENAME(GvSTASH(dstr))
+ )
mro_changes = 2;
else {
const STRLEN len = GvNAMELEN(dstr);
);
}
}
- else if (stype == SVt_PVAV && strEQ(GvNAME((GV*)dstr), "ISA")) {
+ else if (
+ stype == SVt_PVAV && strEQ(GvNAME((GV*)dstr), "ISA")
+ /* The stash may have been detached from the symbol table, so
+ check its name before doing anything. */
+ && GvSTASH(dstr) && HvENAME(GvSTASH(dstr))
+ ) {
sv_magic(sref, dstr, PERL_MAGIC_isa, NULL, 0);
mro_isa_changed_in(GvSTASH(dstr));
}
case SVt_PVGV:
if (isGV_with_GP(sv)) {
if(GvCVu((const GV *)sv) && (stash = GvSTASH(MUTABLE_GV(sv)))
- && HvNAME_get(stash))
+ && HvENAME_get(stash))
mro_method_changed_in(stash);
gp_free(MUTABLE_GV(sv));
if (GvNAME_HEK(sv))