diff options
author | Ton Hospel <me-02@ton.iguana.be> | 2011-05-19 17:05:16 -0700 |
---|---|---|
committer | Father Chrysostomos <sprout@cpan.org> | 2011-05-19 18:01:46 -0700 |
commit | f50383f58716bc0faa50de094d47cad8ad3fcbdb (patch) | |
tree | 30faefd41126b00631bc62d972b2a00f86e604f9 /hv.c | |
parent | 348990471457e062920a311769ddae09a49fa203 (diff) | |
download | perl-f50383f58716bc0faa50de094d47cad8ad3fcbdb.tar.gz |
[perl #85026] Deleting the current iterator in void context
Looking at the delete code I see another strange thing. If the delete
of the current iterator is done with the G_DISCARD flag, the corres-
ponding value is not freed and survives until the lazy deleted entry
gets removed on the next hash iteration. This is easily demonstrated
like this:
perl -wle '
sub DESTROY { print "DESTROY" }
%a=(a=>bless[]);
each %a;
delete $a{a};
print "END"
'
This prints:
END
DESTROY
notice the difference with:
perl -wle '
sub DESTROY { print "DESTROY" }
%hash = (a => bless[]);
each %hash;
$dummy = delete $hash{a}; $dummy = 0;
print "END"
'
This prints:
DESTROY
END
This is easily solved by always replacing the deleted entry value with
&PL_sv_placeholder. It actually simplifies the code a bit except for the
fact that the mro_method_changed from free_hash_ent now has to be done
in hv_delete
Diffstat (limited to 'hv.c')
-rw-r--r-- | hv.c | 24 |
1 files changed, 14 insertions, 10 deletions
@@ -1040,12 +1040,18 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, mro_changes = 1; } - if (d_flags & G_DISCARD) - sv = NULL; - else { - sv = sv_2mortal(HeVAL(entry)); - HeVAL(entry) = &PL_sv_placeholder; - } + if (d_flags & G_DISCARD) { + sv = HeVAL(entry); + if (sv) { + /* deletion of method from stash */ + if (isGV(sv) && isGV_with_GP(sv) && GvCVu(sv) + && HvENAME_get(hv)) + mro_method_changed_in(hv); + SvREFCNT_dec(sv); + sv = NULL; + } + } else sv = sv_2mortal(HeVAL(entry)); + HeVAL(entry) = &PL_sv_placeholder; /* * If a restricted hash, rather than really deleting the entry, put @@ -1053,13 +1059,11 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, * we can still access via not-really-existing key without raising * an error. */ - if (SvREADONLY(hv)) { - SvREFCNT_dec(HeVAL(entry)); - HeVAL(entry) = &PL_sv_placeholder; + if (SvREADONLY(hv)) /* We'll be saving this slot, so the number of allocated keys * doesn't go down, but the number placeholders goes up */ HvPLACEHOLDERS(hv)++; - } else { + else { *oentry = HeNEXT(entry); if (SvOOK(hv) && entry == HvAUX(hv)->xhv_eiter /* HvEITER(hv) */) HvLAZYDEL_on(hv); |