Skip to content
Browse files

[perl #99660] Remove elems from hashes before freeing them

Commit f50383f made the ‘HeVAL(entry) = &PL_sv_placeholder;’ in the
hash-element-deletion code unconditional.  In doing so, it put it
after the if/else statement containing the SvREFCNT_dec.  So the freed
SV was visible in the hash to destructors called by SvREFCNT_dec.
  • Loading branch information...
1 parent be88a5c commit 705822126c5e218f2fe40097f9f1a204474e864b Father Chrysostomos committed Sep 21, 2011
Showing with 17 additions and 3 deletions.
  1. +6 −2 hv.c
  2. +11 −1 t/op/hash.t
View
8 hv.c
@@ -1043,6 +1043,7 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen,
if (d_flags & G_DISCARD) {
sv = HeVAL(entry);
+ HeVAL(entry) = &PL_sv_placeholder;
if (sv) {
/* deletion of method from stash */
if (isGV(sv) && isGV_with_GP(sv) && GvCVu(sv)
@@ -1051,8 +1052,11 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen,
SvREFCNT_dec(sv);
sv = NULL;
}
- } else sv = sv_2mortal(HeVAL(entry));
- HeVAL(entry) = &PL_sv_placeholder;
+ }
+ else {
+ sv = sv_2mortal(HeVAL(entry));
+ HeVAL(entry) = &PL_sv_placeholder;
+ }
/*
* If a restricted hash, rather than really deleting the entry, put
View
12 t/op/hash.t
@@ -8,7 +8,7 @@ BEGIN {
use strict;
-plan tests => 9;
+plan tests => 10;
my %h;
@@ -158,3 +158,13 @@ is($destroyed, 1, 'Timely hash destruction with lvalue keys');
delete $a{a};
ok $gone, 'deleting the current iterator in void context frees the val'
}
+
+# [perl #99660] Deleted hash element visible to destructor
+{
+ my %h;
+ $h{k} = bless [];
+ my $normal_exit;
+ local *::DESTROY = sub { my $x = $h{k}; ++$normal_exit };
+ delete $h{k}; # must be in void context to trigger the bug
+ ok $normal_exit, 'freed hash elems are not visible to DESTROY';
+}

0 comments on commit 7058221

Please sign in to comment.
Something went wrong with that request. Please try again.