X-Git-Url: https://perl5.git.perl.org/perl5.git/blobdiff_plain/3b37eb248baf5af8026a979135e4af0a077172d4..922090f40453dfe5bae918350f2513dc53fa3aba:/hv.c diff --git a/hv.c b/hv.c index 44f385b..20c3531 100644 --- a/hv.c +++ b/hv.c @@ -1544,8 +1544,6 @@ Perl_hv_clear(pTHX_ HV *hv) else { hfreeentries(hv); HvPLACEHOLDERS_set(hv, 0); - if (HvARRAY(hv)) - Zero(HvARRAY(hv), xhv->xhv_max+1 /* HvMAX(hv)+1 */, HE*); if (SvRMAGICAL(hv)) mg_clear(MUTABLE_SV(hv)); @@ -1633,6 +1631,7 @@ STATIC void S_hfreeentries(pTHX_ HV *hv) { int attempts = 100; + STRLEN i = 0; const bool mpm = PL_phase != PERL_PHASE_DESTRUCT && HvENAME(hv); PERL_ARGS_ASSERT_HFREEENTRIES; @@ -1640,72 +1639,63 @@ S_hfreeentries(pTHX_ HV *hv) if (!HvARRAY(hv)) return; - /* we may need multiple attempts to empty the hash, - * since destructors may add things back. */ + /* keep looping until all keys are removed. This may take multiple + * passes through the array, since destructors may add things back. */ - while (1) { + while (((XPVHV*)SvANY(hv))->xhv_keys) { struct xpvhv_aux *iter; HE *entry; - STRLEN i = 0; - - /* free all entries in all slots */ - for (;;) { - HE ** const array = HvARRAY(hv); - - if ( !((XPVHV*) SvANY(hv))->xhv_keys) - break; - - if (SvOOK(hv) && ((iter = HvAUX(hv))) - && ((entry = iter->xhv_eiter)) ) - { - /* the iterator may get resurrected after each - * destructor call, so check each time */ - if (entry && HvLAZYDEL(hv)) { /* was deleted earlier? */ - HvLAZYDEL_off(hv); - hv_free_ent(hv, entry); - } - iter->xhv_riter = -1; /* HvRITER(hv) = -1 */ - iter->xhv_eiter = NULL; /* HvEITER(hv) = NULL */ - } - - entry = array[i]; - if (entry) { - /* Detach this entry. Note that destructors may be - * called which will manipulate this hash, so make sure - * its internal structure remains consistent throughout */ - array[i] = HeNEXT(entry); - ((XPVHV*) SvANY(hv))->xhv_keys--; - - if ( mpm && HeVAL(entry) && isGV(HeVAL(entry)) - && GvHV(HeVAL(entry)) && HvENAME(GvHV(HeVAL(entry))) - ) { - STRLEN klen; - const char * const key = HePV(entry,klen); - if ((klen > 1 && key[klen-1]==':' && key[klen-2]==':') - || (klen == 1 && key[0] == ':')) { - mro_package_moved( - NULL, GvHV(HeVAL(entry)), - (GV *)HeVAL(entry), 0 - ); - } - } + HE ** array; + + if (SvOOK(hv) && ((iter = HvAUX(hv))) + && ((entry = iter->xhv_eiter)) ) + { + /* the iterator may get resurrected after each + * destructor call, so check each time */ + if (entry && HvLAZYDEL(hv)) { /* was deleted earlier? */ + HvLAZYDEL_off(hv); hv_free_ent(hv, entry); /* warning: at this point HvARRAY may have been * re-allocated, HvMAX changed etc */ - continue; } - if (i++ >= HvMAX(hv)) - break; + iter->xhv_riter = -1; /* HvRITER(hv) = -1 */ + iter->xhv_eiter = NULL; /* HvEITER(hv) = NULL */ } - if (((XPVHV*) SvANY(hv))->xhv_keys == 0) - /* Good. No-one added anything this time round. */ - break; - - if (--attempts == 0) { - Perl_die(aTHX_ "panic: hfreeentries failed to free hash - something is repeatedly re-creating entries"); + array = HvARRAY(hv); + entry = array[i]; + if (entry) { + /* Detach and free this entry. Note that destructors may be + * called which will manipulate this hash, so make sure + * its internal structure remains consistent throughout */ + array[i] = HeNEXT(entry); + ((XPVHV*) SvANY(hv))->xhv_keys--; + + if ( mpm && HeVAL(entry) && isGV(HeVAL(entry)) + && GvHV(HeVAL(entry)) && HvENAME(GvHV(HeVAL(entry))) + ) { + STRLEN klen; + const char * const key = HePV(entry,klen); + if ((klen > 1 && key[klen-1]==':' && key[klen-2]==':') + || (klen == 1 && key[0] == ':')) { + mro_package_moved( + NULL, GvHV(HeVAL(entry)), + (GV *)HeVAL(entry), 0 + ); + } + } + hv_free_ent(hv, entry); + /* warning: at this point HvARRAY may have been + * re-allocated, HvMAX changed etc */ + continue; } - } + if (i++ >= HvMAX(hv)) { + i = 0; + if (--attempts == 0) { + Perl_die(aTHX_ "panic: hfreeentries failed to free hash - something is repeatedly re-creating entries"); + } + } + } /* while */ } /* @@ -1745,17 +1735,10 @@ Perl_hv_undef_flags(pTHX_ HV *hv, U32 flags) if (SvOOK(hv)) { struct xpvhv_aux * const aux = HvAUX(hv); struct mro_meta *meta; - bool zeroed = FALSE; if ((name = HvENAME_get(hv))) { - if (PL_phase != PERL_PHASE_DESTRUCT) { - /* This must come at this point in case - mro_isa_changed_in dies. */ - Zero(HvARRAY(hv), xhv->xhv_max+1 /* HvMAX(hv)+1 */, HE*); - zeroed = TRUE; - + if (PL_phase != PERL_PHASE_DESTRUCT) mro_isa_changed_in(hv); - } if (PL_stashcache) (void)hv_delete( PL_stashcache, name, HvENAMELEN_get(hv), G_DISCARD @@ -1789,8 +1772,6 @@ Perl_hv_undef_flags(pTHX_ HV *hv, U32 flags) } if (!aux->xhv_name_u.xhvnameu_name && ! aux->xhv_backreferences) SvFLAGS(hv) &= ~SVf_OOK; - else if (!zeroed) - Zero(HvARRAY(hv), xhv->xhv_max+1 /* HvMAX(hv)+1 */, HE*); } if (!SvOOK(hv)) { Safefree(HvARRAY(hv));