|
|
734417 |
From 316518b545904d368d703005f1622fde03349567 Mon Sep 17 00:00:00 2001
|
|
|
734417 |
From: Father Chrysostomos <sprout@cpan.org>
|
|
|
734417 |
Date: Fri, 21 Sep 2012 22:01:19 -0700
|
|
|
734417 |
Subject: [PATCH] Free iterator when freeing tied hash
|
|
|
734417 |
|
|
|
734417 |
The current iterator was leaking when a tied hash was freed or
|
|
|
734417 |
undefined.
|
|
|
734417 |
|
|
|
734417 |
Since we already have a mechanism, namely HvLAZYDEL, for freeing
|
|
|
734417 |
HvEITER when not referenced elsewhere, we can use that.
|
|
|
734417 |
|
|
|
734417 |
Petr Pisar: Ported to 5.16.3.
|
|
|
734417 |
---
|
|
|
734417 |
hv.c | 3 +++
|
|
|
734417 |
t/op/svleak.t | 15 ++++++++++++++-
|
|
|
734417 |
2 files changed, 17 insertions(+), 1 deletion(-)
|
|
|
734417 |
|
|
|
734417 |
diff --git a/hv.c b/hv.c
|
|
|
734417 |
index a031703..3c35341 100644
|
|
|
734417 |
--- a/hv.c
|
|
|
734417 |
+++ b/hv.c
|
|
|
734417 |
@@ -2346,6 +2346,7 @@ Perl_hv_iternext_flags(pTHX_ HV *hv, I32 flags)
|
|
|
734417 |
if (entry) {
|
|
|
734417 |
sv_setsv(key, HeSVKEY_force(entry));
|
|
|
734417 |
SvREFCNT_dec(HeSVKEY(entry)); /* get rid of previous key */
|
|
|
734417 |
+ HeSVKEY_set(entry, NULL);
|
|
|
734417 |
}
|
|
|
734417 |
else {
|
|
|
734417 |
char *k;
|
|
|
734417 |
@@ -2353,6 +2354,7 @@ Perl_hv_iternext_flags(pTHX_ HV *hv, I32 flags)
|
|
|
734417 |
|
|
|
734417 |
/* one HE per MAGICAL hash */
|
|
|
734417 |
iter->xhv_eiter = entry = new_HE(); /* HvEITER(hv) = new_HE() */
|
|
|
734417 |
+ HvLAZYDEL_on(hv); /* make sure entry gets freed */
|
|
|
734417 |
Zero(entry, 1, HE);
|
|
|
734417 |
Newxz(k, HEK_BASESIZE + sizeof(const SV *), char);
|
|
|
734417 |
hek = (HEK*)k;
|
|
|
734417 |
@@ -2369,6 +2371,7 @@ Perl_hv_iternext_flags(pTHX_ HV *hv, I32 flags)
|
|
|
734417 |
Safefree(HeKEY_hek(entry));
|
|
|
734417 |
del_HE(entry);
|
|
|
734417 |
iter->xhv_eiter = NULL; /* HvEITER(hv) = NULL */
|
|
|
734417 |
+ HvLAZYDEL_off(hv);
|
|
|
734417 |
return NULL;
|
|
|
734417 |
}
|
|
|
734417 |
}
|
|
|
734417 |
diff --git a/t/op/svleak.t b/t/op/svleak.t
|
|
|
734417 |
index 6cfee2e..2f09af3 100644
|
|
|
734417 |
--- a/t/op/svleak.t
|
|
|
734417 |
+++ b/t/op/svleak.t
|
|
|
734417 |
@@ -13,7 +13,7 @@ BEGIN {
|
|
|
734417 |
or skip_all("XS::APItest not available");
|
|
|
734417 |
}
|
|
|
734417 |
|
|
|
734417 |
-plan tests => 22;
|
|
|
734417 |
+plan tests => 23;
|
|
|
734417 |
|
|
|
734417 |
# run some code N times. If the number of SVs at the end of loop N is
|
|
|
734417 |
# greater than (N-1)*delta at the end of loop 1, we've got a leak
|
|
|
734417 |
@@ -163,3 +163,16 @@ leak(2,0,sub { !$^V }, '[perl #109762] version object in boolean context');
|
|
|
734417 |
|
|
|
734417 |
# [perl #114764] Attributes leak scalars
|
|
|
734417 |
leak(2, 0, sub { eval 'my $x : shared' }, 'my $x :shared used to leak');
|
|
|
734417 |
+
|
|
|
734417 |
+# Tied hash iteration was leaking if the hash was freed before itera-
|
|
|
734417 |
+# tion was over.
|
|
|
734417 |
+package t {
|
|
|
734417 |
+ sub TIEHASH { bless [] }
|
|
|
734417 |
+ sub FIRSTKEY { 0 }
|
|
|
734417 |
+}
|
|
|
734417 |
+leak(2, 0, sub {
|
|
|
734417 |
+ my $h = {};
|
|
|
734417 |
+ tie %$h, t;
|
|
|
734417 |
+ each %$h;
|
|
|
734417 |
+ undef $h;
|
|
|
734417 |
+}, 'tied hash iteration does not leak');
|
|
|
734417 |
--
|
|
|
734417 |
1.8.1.4
|
|
|
734417 |
|