summaryrefslogtreecommitdiff
path: root/hv.c
diff options
context:
space:
mode:
authorFather Chrysostomos <sprout@cpan.org>2011-12-20 23:06:20 -0800
committerFather Chrysostomos <sprout@cpan.org>2011-12-20 23:30:04 -0800
commit7ef9d42cef95562593dd30e0fab41e7e09fd0e0e (patch)
treeaa46785cdeac8436243902477a4b0a7c68709a6d /hv.c
parentb89b72572533bd5be1cc901f1d10aadca7e64154 (diff)
downloadperl-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.
Diffstat (limited to 'hv.c')
-rw-r--r--hv.c13
1 files changed, 9 insertions, 4 deletions
diff --git a/hv.c b/hv.c
index 7ce8048075..28ddcd0d67 100644
--- a/hv.c
+++ b/hv.c
@@ -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);