diff options
author | Nicholas Clark <nick@ccl4.org> | 2021-07-26 07:32:46 +0000 |
---|---|---|
committer | Nicholas Clark <nick@ccl4.org> | 2021-09-16 07:06:57 +0000 |
commit | f15a20bce3aaf0956e466389530be470aa2cabfe (patch) | |
tree | 23ccb66f9917a7856ea7a3ef3b10f00623ba3b2c /ext | |
parent | d5a0a5dd15db7407246717e8c3e8891b9ba7c53c (diff) | |
download | perl-f15a20bce3aaf0956e466389530be470aa2cabfe.tar.gz |
Avoid a use-after-free deleting 8-bit keys from stashes
This code path only affects symbol tables, and can't be reached by regular
Perl code. It is only reachable using the XS API to delete a key from a
stash where the key was in the 8-bit range but passed in UTF-8 encoded.
This has been in the code since it was added in Oct 2010 by commit
35759254f69c7bfa:
Rename stashes when they move around
Also there is no need to call SvPV() on keysv in S_hv_delete_common() as
its caller has always already done this. This entire code is not KISS.
Diffstat (limited to 'ext')
-rw-r--r-- | ext/XS-APItest/t/hash.t | 19 |
1 files changed, 19 insertions, 0 deletions
diff --git a/ext/XS-APItest/t/hash.t b/ext/XS-APItest/t/hash.t index 29d5803584..5d3357e888 100644 --- a/ext/XS-APItest/t/hash.t +++ b/ext/XS-APItest/t/hash.t @@ -325,6 +325,25 @@ pass("hv_store works on the hint hash"); is(sv_magic_mycopy_count(\%h), 4); } +{ + # There are two API variants - hv_delete and hv_delete_ent. The Perl + # interpreter exclusively uses hv_delete_ent. Only XS code uses hv_delete. + # Hence the problem case could only be triggered by XS code called on + # symbol tables, and with particular non-ASCII keys: + + # Deleting a key with WASUTF from a stash used to trigger a use-after free: + my $key = "\xFF\x{100}"; + chop $key; + ++$main::{$key}; + is(XS::APItest::Hash::delete(\%main::, $key), 1, + "hv_delete doesn't trigger a use-after free"); + + # Perl code has always used this API, which never had the problem: + ++$main::{$key}; + is(XS::APItest::Hash::delete_ent(\%main::, $key), 1, + "hv_delete_ent never triggered a use-after free, but test it anyway"); +} + done_testing; exit; |