summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFather Chrysostomos <sprout@cpan.org>2011-06-24 08:17:28 -0700
committerFather Chrysostomos <sprout@cpan.org>2011-06-24 08:19:28 -0700
commit6d1c68e64c4dbbb1c7e8a28de678cd3247649bad (patch)
tree429f168000f8db2ec45dd6e3ff555fb90e465f08
parentf4e68e82b126f2b2bfde4c660b1045c1e4a69455 (diff)
downloadperl-6d1c68e64c4dbbb1c7e8a28de678cd3247649bad.tar.gz
[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.
-rw-r--r--hv.c5
-rw-r--r--sv.c4
2 files changed, 5 insertions, 4 deletions
diff --git a/hv.c b/hv.c
index a230c167fc..c8ed63c3e3 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 2c97ccecaf..04e040c20c 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: */