This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
[perl #93454] Free deleted iterator when freeing hash
authorFather Chrysostomos <sprout@cpan.org>
Fri, 24 Jun 2011 15:17:28 +0000 (08:17 -0700)
committerFather Chrysostomos <sprout@cpan.org>
Fri, 24 Jun 2011 15:19:28 +0000 (08:19 -0700)
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.

hv.c
sv.c

diff --git a/hv.c b/hv.c
index a230c16..c8ed63c 100644 (file)
--- 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 (file)
--- 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: */