diff options
author | Father Chrysostomos <sprout@cpan.org> | 2011-12-20 23:06:20 -0800 |
---|---|---|
committer | Father Chrysostomos <sprout@cpan.org> | 2011-12-20 23:30:04 -0800 |
commit | 7ef9d42cef95562593dd30e0fab41e7e09fd0e0e (patch) | |
tree | aa46785cdeac8436243902477a4b0a7c68709a6d | |
parent | b89b72572533bd5be1cc901f1d10aadca7e64154 (diff) | |
download | perl-7ef9d42cef95562593dd30e0fab41e7e09fd0e0e.tar.gz |
Fixing crash in hint.t
The test that was added in 95cf23680e tickled another bug in the same
code in Perl_hv_copy_hints_hv than the one it fixed, but not on the
committer’s machine.
Not only can a HE from a tied hash have a null entry, but it can also
have an SV for its key. Treating it as a hek and trying to read flags
from it may result in other code being told to free something it
shouldn’t because the SV, when looked at as a hek, appeared to have
the HVhek_FREEKEY flag.
-rw-r--r-- | hv.c | 13 |
1 files changed, 9 insertions, 4 deletions
@@ -1464,12 +1464,17 @@ Perl_hv_copy_hints_hv(pTHX_ HV *const ohv) hv_iterinit(ohv); while ((entry = hv_iternext_flags(ohv, 0))) { SV *const sv = newSVsv(HeVAL(entry)); - SV *heksv = newSVhek(HeKEY_hek(entry)); + SV *heksv = HeSVKEY(entry); + if (!heksv && sv) heksv = newSVhek(HeKEY_hek(entry)); if (sv) sv_magic(sv, NULL, PERL_MAGIC_hintselem, (char *)heksv, HEf_SVKEY); - SvREFCNT_dec(heksv); - (void)hv_store_flags(hv, HeKEY(entry), HeKLEN(entry), - sv, HeHASH(entry), HeKFLAGS(entry)); + if (heksv == HeSVKEY(entry)) + (void)hv_store_ent(hv, heksv, sv, 0); + else { + (void)hv_common(hv, heksv, HeKEY(entry), HeKLEN(entry), + HeKFLAGS(entry), HV_FETCH_ISSTORE|HV_FETCH_JUST_SV, sv, HeHASH(entry)); + SvREFCNT_dec(heksv); + } } HvRITER_set(ohv, riter); HvEITER_set(ohv, eiter); |