summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFather Chrysostomos <sprout@cpan.org>2011-12-24 07:05:42 -0800
committerFather Chrysostomos <sprout@cpan.org>2011-12-24 16:14:31 -0800
commit746f6409435f8adf48a22fa3c61d95758160b655 (patch)
tree2e01962418518b71f6d2a56e7a5fc25a2662a944
parent3f4d1d7873e4e02f3801f2982565de93d2127bbd (diff)
downloadperl-746f6409435f8adf48a22fa3c61d95758160b655.tar.gz
Don’t crash when writing to null hash elem
It’s possible for XS code to create hash entries with null values. pp_helem and pp_slice were not taking that into account. In fact, the core produces such hash entries, but they are rarely visible from Perl. It’s good to check for them anyway.
-rw-r--r--ext/XS-APItest/t/hash.t13
-rw-r--r--pp.c4
-rw-r--r--pp_hot.c4
3 files changed, 17 insertions, 4 deletions
diff --git a/ext/XS-APItest/t/hash.t b/ext/XS-APItest/t/hash.t
index f66edfa1f5..06983c570d 100644
--- a/ext/XS-APItest/t/hash.t
+++ b/ext/XS-APItest/t/hash.t
@@ -245,6 +245,19 @@ sub test_precomputed_hashes {
'newHVhv on tied hash';
}
+# helem on entry with null value
+# This is actually a test for a Perl operator, not an XS API test. But it
+# requires a hash that can only be produced by XS (although recently it
+# could be encountered when tying hint hashes).
+{
+ my %h;
+ fill_hash_with_nulls(\%h);
+ eval{ $h{84} = 1 };
+ pass 'no crash when writing to hash elem with null value';
+ eval{ @h{85} = 1 };
+ pass 'no crash when writing to hash elem with null value via slice';
+}
+
done_testing;
exit;
diff --git a/pp.c b/pp.c
index c9d72b8a99..dd67264147 100644
--- a/pp.c
+++ b/pp.c
@@ -4629,7 +4629,7 @@ PP(pp_hslice)
svp = he ? &HeVAL(he) : NULL;
if (lval) {
- if (!svp || *svp == &PL_sv_undef) {
+ if (!svp || !*svp || *svp == &PL_sv_undef) {
DIE(aTHX_ PL_no_helem_sv, SVfARG(keysv));
}
if (localizing) {
@@ -4642,7 +4642,7 @@ PP(pp_hslice)
SAVEHDELETE(hv, keysv);
}
}
- *MARK = svp ? *svp : &PL_sv_undef;
+ *MARK = svp && *svp ? *svp : &PL_sv_undef;
}
if (GIMME != G_ARRAY) {
MARK = ORIGMARK;
diff --git a/pp_hot.c b/pp_hot.c
index a2d6f9140e..99cd2e199a 100644
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -1773,7 +1773,7 @@ PP(pp_helem)
he = hv_fetch_ent(hv, keysv, lval && !defer, hash);
svp = he ? &HeVAL(he) : NULL;
if (lval) {
- if (!svp || *svp == &PL_sv_undef) {
+ if (!svp || !*svp || *svp == &PL_sv_undef) {
SV* lv;
SV* key2;
if (!defer) {
@@ -1803,7 +1803,7 @@ PP(pp_helem)
RETURN;
}
}
- sv = (svp ? *svp : &PL_sv_undef);
+ sv = (svp && *svp ? *svp : &PL_sv_undef);
/* Originally this did a conditional C<sv = sv_mortalcopy(sv)>; this
* was to make C<local $tied{foo} = $tied{foo}> possible.
* However, it seems no longer to be needed for that purpose, and