diff options
author | Father Chrysostomos <sprout@cpan.org> | 2010-10-29 20:45:34 -0700 |
---|---|---|
committer | Father Chrysostomos <sprout@cpan.org> | 2010-10-29 21:50:24 -0700 |
commit | 00169e2cdde29138824a7bf6b66d5875aaa8278d (patch) | |
tree | aeb3b50ba3698ec9d26053d42e414fda70a983ba | |
parent | bc56db2a697ebe59892fabdcfa5aa910ed4f2885 (diff) | |
download | perl-00169e2cdde29138824a7bf6b66d5875aaa8278d.tar.gz |
Switch the core MRO code over to HvENAME
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.
-rw-r--r-- | hv.c | 8 | ||||
-rw-r--r-- | mg.c | 4 | ||||
-rw-r--r-- | mro.c | 18 | ||||
-rw-r--r-- | pp.c | 4 | ||||
-rw-r--r-- | scope.c | 2 | ||||
-rw-r--r-- | sv.c | 25 |
6 files changed, 41 insertions, 20 deletions
@@ -1481,7 +1481,7 @@ Perl_hv_free_ent(pTHX_ HV *hv, register HE *entry) 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) { @@ -1568,7 +1568,7 @@ Perl_hv_clear(pTHX_ HV *hv) HvREHASH_off(hv); reset: if (SvOOK(hv)) { - if(HvNAME_get(hv)) + if(HvENAME_get(hv)) mro_isa_changed_in(hv); HvEITER_set(hv, NULL); } @@ -1852,11 +1852,11 @@ Perl_hv_undef(pTHX_ HV *hv) 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); @@ -1630,7 +1630,9 @@ Perl_magic_clearisa(pTHX_ SV *sv, MAGIC *mg) : (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; @@ -215,7 +215,11 @@ S_mro_get_linear_isa_dfs(pTHX_ HV *stash, U32 level) 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"); @@ -438,8 +442,8 @@ Perl_mro_isa_changed_in3(pTHX_ HV* stash, const char *stashname, 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 */); @@ -692,7 +696,7 @@ Perl_mro_package_moved(pTHX_ HV * const stash, HV * const oldstash, stashentry && *stashentry && (substash = GvHV(*stashentry)) ) - || (oldsubstash && HvNAME(oldsubstash)) + || (oldsubstash && HvENAME_get(oldsubstash)) ) { /* Add :: and the key (minus the trailing ::) @@ -782,7 +786,7 @@ Perl_mro_package_moved(pTHX_ HV * const stash, HV * const oldstash, } set_names: - if(oldstash && HvNAME(oldstash)) { + if(oldstash && HvENAME_get(oldstash)) { if(PL_stashcache) (void) hv_delete(PL_stashcache, newname, newname_len, G_DISCARD); @@ -824,8 +828,8 @@ via, C<mro::method_changed_in(classname)>. 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; @@ -854,11 +854,11 @@ PP(pp_undef) 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)); @@ -859,7 +859,7 @@ Perl_leave_scope(pTHX_ I32 base) 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; @@ -3607,13 +3607,18 @@ S_glob_assign_glob(pTHX_ SV *const dstr, SV *const sstr, const int dtype) } /* 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; } @@ -3621,7 +3626,12 @@ S_glob_assign_glob(pTHX_ SV *const dstr, SV *const sstr, const int dtype) 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); @@ -3781,7 +3791,12 @@ S_glob_assign_ref(pTHX_ SV *const dstr, SV *const sstr) ); } } - 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)); } @@ -5991,7 +6006,7 @@ Perl_sv_clear(pTHX_ SV *const orig_sv) 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)) |