diff options
author | Father Chrysostomos <sprout@cpan.org> | 2011-04-15 22:33:31 -0700 |
---|---|---|
committer | Father Chrysostomos <sprout@cpan.org> | 2011-04-15 22:34:16 -0700 |
commit | 1f656fcf060e343780f7a91a2ce567e8a9de9414 (patch) | |
tree | 1c24080e8393811be538f104daae330cdb966498 /mro.c | |
parent | 2f81e8f3910ca00e129de843e034fb70a0bcc905 (diff) | |
download | perl-1f656fcf060e343780f7a91a2ce567e8a9de9414.tar.gz |
Followup to 088225f/[perl #88132]: packages ending with :
Commit 088225f was not sufficient to fix the regression. It still
exists for packages whose names end with a single colon.
I discovered this when trying to determine why RDF::Trine was crashing
with 5.14-to-be.
In trying to write tests for it, I ended up triggering the same crash
that RDF::Trine is having, but in a different way.
In the end, it was easier to fix about three or four bugs (depending
on how you count them), rather than try to fix only the regression
that #88132 deals with (isa caches not updating when packages ending
with colons are aliased), as they are all intertwined.
The changes are as follows:
Concerning the if (!(flags & ~GV_NOADD_MASK)...) statement in
gv_stashpvn: Normally, gv_fetchpvn_flags (which it calls and whose
retval is assigned to tmpgv) returns NULL if it has not been told
to add anything and if the gv requested looks like a stash gv (ends
with ::). If the number of colons is odd (foo:::), that code path is
bypassed, so gv_stashpvn returns a GV without a hash. So gv_stashpvn
tries to used that NULL hash and crashes. It should instead return
NULL, to be consistent with the two-colon case.
Blindly assigning a name to a stash does not work if the stash has
multiple effective names. A call to mro_package_moved is required as
well. So what gv_stashpvn was doing was insufficient.
The parts of the mro code that check for globs or stash elems that
contain stashes by looking for :: at the end of the name now take into
account that the name might consist of a single : instead.
Diffstat (limited to 'mro.c')
-rw-r--r-- | mro.c | 61 |
1 files changed, 43 insertions, 18 deletions
@@ -738,9 +738,9 @@ Perl_mro_package_moved(pTHX_ HV * const stash, HV * const oldstash, ) return; } assert(SvOOK(GvSTASH(gv))); - assert(GvNAMELEN(gv) > 1); + assert(GvNAMELEN(gv)); assert(GvNAME(gv)[GvNAMELEN(gv) - 1] == ':'); - assert(GvNAME(gv)[GvNAMELEN(gv) - 2] == ':'); + assert(GvNAMELEN(gv) == 1 || GvNAME(gv)[GvNAMELEN(gv) - 2] == ':'); name_count = HvAUX(GvSTASH(gv))->xhv_name_count; if (!name_count) { name_count = 1; @@ -752,13 +752,17 @@ Perl_mro_package_moved(pTHX_ HV * const stash, HV * const oldstash, } if (name_count == 1) { if (HEK_LEN(*namep) == 4 && strnEQ(HEK_KEY(*namep), "main", 4)) { - namesv = newSVpvs_flags("", SVs_TEMP); + namesv = GvNAMELEN(gv) == 1 + ? newSVpvs_flags(":", SVs_TEMP) + : newSVpvs_flags("", SVs_TEMP); } else { namesv = sv_2mortal(newSVhek(*namep)); - sv_catpvs(namesv, "::"); + if (GvNAMELEN(gv) == 1) sv_catpvs(namesv, ":"); + else sv_catpvs(namesv, "::"); } - sv_catpvn(namesv, GvNAME(gv), GvNAMELEN(gv) - 2); + if (GvNAMELEN(gv) != 1) + sv_catpvn(namesv, GvNAME(gv), GvNAMELEN(gv) - 2); /* skip trailing :: */ } else { @@ -766,13 +770,18 @@ Perl_mro_package_moved(pTHX_ HV * const stash, HV * const oldstash, namesv = sv_2mortal((SV *)newAV()); while (name_count--) { if(HEK_LEN(*namep) == 4 && strnEQ(HEK_KEY(*namep), "main", 4)){ - aname = newSVpvs(""); namep++; + aname = GvNAMELEN(gv) == 1 + ? newSVpvs(":") + : newSVpvs(""); + namep++; } else { aname = newSVhek(*namep++); - sv_catpvs(aname, "::"); + if (GvNAMELEN(gv) == 1) sv_catpvs(aname, ":"); + else sv_catpvs(aname, "::"); } - sv_catpvn(aname, GvNAME(gv), GvNAMELEN(gv) - 2); + if (GvNAMELEN(gv) != 1) + sv_catpvn(aname, GvNAME(gv), GvNAMELEN(gv) - 2); /* skip trailing :: */ av_push((AV *)namesv, aname); } @@ -1069,7 +1078,8 @@ S_mro_gather_and_rename(pTHX_ HV * const stashes, HV * const seen_stashes, if (!isGV(HeVAL(entry))) continue; key = hv_iterkey(entry, &len); - if(len > 1 && key[len-2] == ':' && key[len-1] == ':') { + if ((len > 1 && key[len-2] == ':' && key[len-1] == ':') + || (len == 1 && key[0] == ':')) { HV * const oldsubstash = GvHV(HeVAL(entry)); SV ** const stashentry = stash ? hv_fetch(stash, key, len, 0) : NULL; @@ -1096,15 +1106,22 @@ S_mro_gather_and_rename(pTHX_ HV * const stashes, HV * const seen_stashes, subname = sv_2mortal((SV *)newAV()); while (items--) { aname = newSVsv(*svp++); - sv_catpvs(aname, "::"); - sv_catpvn(aname, key, len-2); + if (len == 1) + sv_catpvs(aname, ":"); + else { + sv_catpvs(aname, "::"); + sv_catpvn(aname, key, len-2); + } av_push((AV *)subname, aname); } } else { subname = sv_2mortal(newSVsv(namesv)); - sv_catpvs(subname, "::"); - sv_catpvn(subname, key, len-2); + if (len == 1) sv_catpvs(subname, ":"); + else { + sv_catpvs(subname, "::"); + sv_catpvn(subname, key, len-2); + } } mro_gather_and_rename( stashes, seen_stashes, @@ -1138,7 +1155,8 @@ S_mro_gather_and_rename(pTHX_ HV * const stashes, HV * const seen_stashes, if (!isGV(HeVAL(entry))) continue; key = hv_iterkey(entry, &len); - if(len > 1 && key[len-2] == ':' && key[len-1] == ':') { + if ((len > 1 && key[len-2] == ':' && key[len-1] == ':') + || (len == 1 && key[0] == ':')) { HV *substash; /* If this entry was seen when we iterated through the @@ -1164,15 +1182,22 @@ S_mro_gather_and_rename(pTHX_ HV * const stashes, HV * const seen_stashes, subname = sv_2mortal((SV *)newAV()); while (items--) { aname = newSVsv(*svp++); - sv_catpvs(aname, "::"); - sv_catpvn(aname, key, len-2); + if (len == 1) + sv_catpvs(aname, ":"); + else { + sv_catpvs(aname, "::"); + sv_catpvn(aname, key, len-2); + } av_push((AV *)subname, aname); } } else { subname = sv_2mortal(newSVsv(namesv)); - sv_catpvs(subname, "::"); - sv_catpvn(subname, key, len-2); + if (len == 1) sv_catpvs(subname, ":"); + else { + sv_catpvs(subname, "::"); + sv_catpvn(subname, key, len-2); + } } mro_gather_and_rename( stashes, seen_stashes, |