diff options
author | Father Chrysostomos <sprout@cpan.org> | 2010-10-12 22:07:17 -0700 |
---|---|---|
committer | Father Chrysostomos <sprout@cpan.org> | 2010-10-12 22:09:01 -0700 |
commit | 62c1e33fbe385549e958f7699d17bfc9e0cd1ca2 (patch) | |
tree | 6381129bf0b8ff17d2a6d39ec6c5491a61663c89 /mro.c | |
parent | 989690ac118eb981de3afdd9b2e092362f453d31 (diff) | |
download | perl-62c1e33fbe385549e958f7699d17bfc9e0cd1ca2.tar.gz |
[perl #78362] Make mro_package_moved check for recursion
The existence of main::main::... caused mro_package_moved to break
Text::Template, and probably Acme::Meta as well.
Diffstat (limited to 'mro.c')
-rw-r--r-- | mro.c | 31 |
1 files changed, 25 insertions, 6 deletions
@@ -589,26 +589,35 @@ non-existent packages that have corresponding entries in C<stash>. void Perl_mro_package_moved(pTHX_ HV * const stash, const HV * const oldstash, const GV * const gv, const char *newname, - STRLEN newname_len) + I32 newname_len) { register XPVHV* xhv; register HE *entry; I32 riter = -1; HV *seen = NULL; + /* If newname_len is negative, it is actually the call depth (negated). + */ + const I32 level = newname_len < 0 ? newname_len : 0; assert(stash || oldstash); assert(oldstash || gv || newname); + if(level < -100) return; + if(!newname && oldstash) { newname = HvNAME_get(oldstash); newname_len = HvNAMELEN_get(oldstash); } if(!newname && gv) { SV * const namesv = sv_newmortal(); + STRLEN len; gv_fullname4(namesv, gv, NULL, 0); - newname = SvPV_const(namesv, newname_len); - newname_len -= 2; /* skip trailing :: */ + newname = SvPV_const(namesv, len); + newname_len = len - 2; /* skip trailing :: */ } + /* XXX This relies on the fact that package names cannot contain nulls. + */ + if(newname_len < 0) newname_len = strlen(newname); mro_isa_changed_in3((HV *)oldstash, newname, newname_len); @@ -649,13 +658,17 @@ Perl_mro_package_moved(pTHX_ HV * const stash, const HV * const oldstash, SV ** const stashentry = stash ? hv_fetch(stash, key, len, 0) : NULL; HV *substash; + + /* Avoid main::main::main::... */ + if(oldsubstash == oldstash) continue; + if( stashentry && *stashentry && (substash = GvHV(*stashentry)) && HvNAME(substash) ) mro_package_moved( - substash, oldsubstash, NULL, NULL, 0 + substash, oldsubstash, NULL, NULL, level-1 ); else if(oldsubstash && HvNAME(oldsubstash)) mro_isa_changed_in(oldsubstash); @@ -697,15 +710,21 @@ Perl_mro_package_moved(pTHX_ HV * const stash, const HV * const oldstash, substash = GvHV(HeVAL(entry)); if(substash && HvNAME(substash)) { + SV *namesv; + + /* Avoid checking main::main::main::... */ + if(substash == stash) continue; + /* Add :: and the key (minus the trailing ::) to newname. */ - SV *namesv + namesv = newSVpvn_flags(newname, newname_len, SVs_TEMP); sv_catpvs(namesv, "::"); sv_catpvn(namesv, key, len-2); mro_package_moved( substash, NULL, NULL, - SvPV_nolen_const(namesv), newname_len+len + SvPV_nolen_const(namesv), + level-1 ); } } |