summaryrefslogtreecommitdiff
path: root/hv.c
diff options
context:
space:
mode:
authorNicholas Clark <nick@ccl4.org>2009-08-20 15:56:18 +0100
committerNicholas Clark <nick@ccl4.org>2009-08-20 15:56:18 +0100
commitc3acb9e0760135dfd888c0ee1b415777d784aabc (patch)
treed019d57d26831556e71bd031fcfb0433b0b73560 /hv.c
parente7598a06d704c8e12489be3a9098367ae55f5a89 (diff)
downloadperl-c3acb9e0760135dfd888c0ee1b415777d784aabc.tar.gz
Perl_newHVhv() should copy immortal values as-is, such as PL_sv_undef
Currently it calls newSVsv() always, which copies the value, but the immortal SVs are used as much for their addresses as their values. You can't get the immortals into HVs from Perl-space, except for PL_sv_placeholder, and any hash with those will take the else block, where the call to Perl_hv_iternext_flags() won't be returning placeholders anyway. Hence If XS code has gone to the trouble to get the "impossible" in there, they had a reason for it. I am assuming that Perl_hv_copy_hints_hv() should stay as-is, as it is documented that only strings and integers are supported values for %^H.
Diffstat (limited to 'hv.c')
-rw-r--r--hv.c8
1 files changed, 5 insertions, 3 deletions
diff --git a/hv.c b/hv.c
index a5221a8d29..ee3a67eba6 100644
--- a/hv.c
+++ b/hv.c
@@ -1379,8 +1379,9 @@ Perl_newHVhv(pTHX_ HV *ohv)
const STRLEN len = HeKLEN(oent);
const int flags = HeKFLAGS(oent);
HE * const ent = new_HE();
+ SV *const val = HeVAL(oent);
- HeVAL(ent) = newSVsv(HeVAL(oent));
+ HeVAL(ent) = SvIMMORTAL(val) ? val : newSVsv(val);
HeKEY_hek(ent)
= shared ? share_hek_flags(key, len, hash, flags)
: save_hek_flags(key, len, hash, flags);
@@ -1411,9 +1412,10 @@ Perl_newHVhv(pTHX_ HV *ohv)
hv_iterinit(ohv);
while ((entry = hv_iternext_flags(ohv, 0))) {
+ SV *const val = HeVAL(entry);
(void)hv_store_flags(hv, HeKEY(entry), HeKLEN(entry),
- newSVsv(HeVAL(entry)), HeHASH(entry),
- HeKFLAGS(entry));
+ SvIMMORTAL(val) ? val : newSVsv(val),
+ HeHASH(entry), HeKFLAGS(entry));
}
HvRITER_set(ohv, riter);
HvEITER_set(ohv, eiter);