Calling Perl_hv_clear_placeholders while the hash iterator was active
Nicholas Clark [Sat, 31 Dec 2005 16:57:32 +0000 (16:57 +0000)]
would turn lazy delete on, causing the hash to become corrupted at the
next iterator change.

p4raw-id: //depot/perl@26551

hv.c
lib/Hash/Util.t

diff --git a/hv.c b/hv.c
index 7452b1e..69c951c 100644 (file)
--- a/hv.c
+++ b/hv.c
@@ -1617,7 +1617,7 @@ Perl_hv_clear_placeholders(pTHX_ HV *hv)
                *oentry = HeNEXT(entry);
                if (first && !*oentry)
                    HvFILL(hv)--; /* This linked list is now empty.  */
-               if (HvEITER_get(hv))
+               if (entry == HvEITER_get(hv))
                    HvLAZYDEL_on(hv);
                else
                    hv_free_ent(hv, entry);
index 8ed557f..adce3d1 100644 (file)
@@ -6,7 +6,7 @@ BEGIN {
         chdir 't';
     }
 }
-use Test::More tests => 173;
+use Test::More tests => 179;
 use strict;
 
 my @Exported_Funcs;
@@ -323,3 +323,22 @@ ok($hash_seed >= 0, "hash_seed $hash_seed");
        is ($counter, 0, "0 objects after clear $state");
     }
 }
+
+{
+    my %hash = map {$_,$_} qw(fwiffffff foosht teeoo);
+    lock_keys(%hash);
+    delete $hash{fwiffffff};
+    is (scalar keys %hash, 2);
+    unlock_keys(%hash);
+    is (scalar keys %hash, 2);
+
+    my ($first, $value) = each %hash;
+    is ($hash{$first}, $value, "Key has the expected value before the lock");
+    lock_keys(%hash);
+    is ($hash{$first}, $value, "Key has the expected value after the lock");
+
+    my ($second, $v2) = each %hash;
+
+    is ($hash{$first}, $value, "Still correct after iterator advances");
+    is ($hash{$second}, $v2, "Other key has the expected value");
+}