From: Father Chrysostomos Date: Fri, 24 Jun 2011 15:17:28 +0000 (-0700) Subject: [perl #93454] Free deleted iterator when freeing hash X-Git-Tag: accepted/trunk/20130322.191538~3523 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=6d1c68e64c4dbbb1c7e8a28de678cd3247649bad;p=platform%2Fupstream%2Fperl.git [perl #93454] Free deleted iterator when freeing hash Commit 7d6175e, which did a fix-up after commit e0171a1a3, which introduced hfree_next_entry, did not account for the fact that hfree_next_entry frees the hash iterator before removing and returning the next value. It changed the callers to check the number of keys to determine whether anything else needed to be freed, which meant that hfree_next_entry was called one time less than necessary on hashes whose current iterator had been deleted and which consequently appeared empty. This fixes that. I don’t know how to test it, but the string table warnings were caus- ing test failures on VMS, so maybe that’s good enough. --- diff --git a/hv.c b/hv.c index a230c16..c8ed63c 100644 --- a/hv.c +++ b/hv.c @@ -1663,11 +1663,12 @@ S_hfreeentries(pTHX_ HV *hv) { STRLEN index = 0; XPVHV * const xhv = (XPVHV*)SvANY(hv); + SV *sv; PERL_ARGS_ASSERT_HFREEENTRIES; - while (xhv->xhv_keys) { - SvREFCNT_dec(Perl_hfree_next_entry(aTHX_ hv, &index)); + while ((sv = Perl_hfree_next_entry(aTHX_ hv, &index))||xhv->xhv_keys) { + SvREFCNT_dec(sv); } } diff --git a/sv.c b/sv.c index 2c97cce..04e040c 100644 --- a/sv.c +++ b/sv.c @@ -6180,7 +6180,8 @@ Perl_sv_clear(pTHX_ SV *const orig_sv) goto free_body; } } else if (SvTYPE(iter_sv) == SVt_PVHV) { - if (!HvTOTALKEYS((HV *)iter_sv)) { + sv = Perl_hfree_next_entry(aTHX_ (HV*)iter_sv, &hash_index); + if (!sv && !HvTOTALKEYS((HV *)iter_sv)) { /* no more elements of current HV to free */ sv = iter_sv; type = SvTYPE(sv); @@ -6197,7 +6198,6 @@ Perl_sv_clear(pTHX_ SV *const orig_sv) assert(!HvARRAY((HV*)sv)); goto free_body; } - sv = Perl_hfree_next_entry(aTHX_ (HV*)iter_sv, &hash_index); } /* unrolled SvREFCNT_dec and sv_free2 follows: */