summaryrefslogtreecommitdiff
path: root/lib/B/Deparse.t
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2020-01-02 14:00:23 +0000
committerDavid Mitchell <davem@iabyn.com>2020-01-02 14:42:28 +0000
commitb790ed71bdb9ac73a66f9dc2639f19950391ed45 (patch)
treec82435c7c7558a253c62af723d7e18e85f95fae2 /lib/B/Deparse.t
parent4eeaed3791af175b5840f626d4d1a4e3b4cb3543 (diff)
downloadperl-b790ed71bdb9ac73a66f9dc2639f19950391ed45.tar.gz
OP_MULTIDEREF: avoid trailing null aux byte
GH #17301 The aux array in an OP_MULTIDEREF op consists of an action word containing as many actions as will fit shifted together, followed by words containing the arguments for those actions. Then another action word, and so on. The code in S_maybe_multideref() which creates those ops was reserving a new slot in the aux array for a new action word when the old one became full. If it then turned out that no more actions were needed, this extra slot was harmlessly filled with a zero. However it turns out that the B::UNOP_AUX::aux_list() introspection method would, under those circumstances, claim to have returned one more SV on the stack than it actually had, leading to SEGVs etc. I could have fixed aux_list() directly to cope with an extra null word, but instead I did the more general fix of ensuring that S_maybe_multideref() never adds an extra null word in the first place. The test added to ext/B/t/b.t fails before this commit; the new test in lib/B/Deparse.t doesn't, but was added for completeness.
Diffstat (limited to 'lib/B/Deparse.t')
-rw-r--r--lib/B/Deparse.t15
1 files changed, 15 insertions, 0 deletions
diff --git a/lib/B/Deparse.t b/lib/B/Deparse.t
index 2406266a71..07c915067e 100644
--- a/lib/B/Deparse.t
+++ b/lib/B/Deparse.t
@@ -3062,3 +3062,18 @@ $#{$s;} = 1;
# TODO doesn't preserve backslash
my @a;
my $s = "$a[0]\[1]";
+####
+# GH #17301 aux_list() sometimes returned wrong #args
+my($r, $h);
+$r = $h->{'i'};
+$r = $h->{'i'}{'j'};
+$r = $h->{'i'}{'j'}{'k'};
+$r = $h->{'i'}{'j'}{'k'}{'l'};
+$r = $h->{'i'}{'j'}{'k'}{'l'}{'m'};
+$r = $h->{'i'}{'j'}{'k'}{'l'}{'m'}{'n'};
+$r = $h->{'i'}{'j'}{'k'}{'l'}{'m'}{'n'}{'o'};
+$r = $h->{'i'}{'j'}{'k'}{'l'}{'m'}{'n'}{'o'}{'p'};
+$r = $h->{'i'}{'j'}{'k'}{'l'}{'m'}{'n'}{'o'}{'p'}{'q'};
+$r = $h->{'i'}{'j'}{'k'}{'l'}{'m'}{'n'}{'o'}{'p'}{'q'}{'r'};
+$r = $h->{'i'}{'j'}{'k'}{'l'}{'m'}{'n'}{'o'}{'p'}{'q'}{'r'}{'s'};
+$r = $h->{'i'}{'j'}{'k'}{'l'}{'m'}{'n'}{'o'}{'p'}{'q'}{'r'}{'s'}{'t'};