summaryrefslogtreecommitdiff
path: root/pp_hot.c
diff options
context:
space:
mode:
authorFather Chrysostomos <sprout@cpan.org>2018-02-18 16:12:11 -0800
committerFather Chrysostomos <sprout@cpan.org>2018-02-18 16:29:35 -0800
commit9ef753fe465d865deeba96157242bc98c0afe412 (patch)
tree15d7e5eb8eae642b4fccd1872bf40e80f3e9eb1c /pp_hot.c
parent7406cffe8ec122fcc2500115f8ed1742385893e1 (diff)
downloadperl-9ef753fe465d865deeba96157242bc98c0afe412.tar.gz
Fix ary shifting when sparse ary is passed to sub
This commit fixes #132729 in the specific case where a nonexistent element within a sparse array is passed to a subroutine. Prior to this commit, some_sub($sparse_array[$n]) where $n <= $#sparse_array and the element does not exist, would exhi- bit erroneous behaviour if some_sub shifted or unshifted the original @sparse_array. Any ‘holes’ (nonexistent elements) in the array would show up in @_ as deferred element (defelem) scalars, magic scalars that remember their index in the array. This index is not updated and gets out of synch when the array is shifted. This commit fixes the bug for elements within the array by using the new ‘nonelem’ magic introduced a few commits ago. It stores within the array a magic scalar that is marked as being nonexistent. It also reduced the number of scalars that need to be created if such a sub call happens repeatedly.
Diffstat (limited to 'pp_hot.c')
-rw-r--r--pp_hot.c38
1 files changed, 25 insertions, 13 deletions
diff --git a/pp_hot.c b/pp_hot.c
index 24c86e46fe..328d6f0659 100644
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -3630,13 +3630,19 @@ PP(pp_multideref)
if (!defer)
DIE(aTHX_ PL_no_aelem, elem);
len = av_tindex(av);
- sv = sv_2mortal(newSVavdefelem(av,
- /* Resolve a negative index now, unless it points
- * before the beginning of the array, in which
- * case record it for error reporting in
- * magic_setdefelem. */
- elem < 0 && len + elem >= 0
- ? len + elem : elem, 1));
+ /* Resolve a negative index that falls within
+ * the array. Leave it negative it if falls
+ * outside the array. */
+ if (elem < 0 && len + elem >= 0)
+ elem = len + elem;
+ if (elem >= 0 && elem <= len)
+ /* Falls within the array. */
+ sv = av_nonelem(av,elem);
+ else
+ /* Falls outside the array. If it is neg-
+ ative, magic_setdefelem will use the
+ index for error reporting. */
+ sv = sv_2mortal(newSVavdefelem(av,elem,1));
}
else {
if (UNLIKELY(localizing)) {
@@ -5363,12 +5369,18 @@ PP(pp_aelem)
if (!defer)
DIE(aTHX_ PL_no_aelem, elem);
len = av_tindex(av);
- mPUSHs(newSVavdefelem(av,
- /* Resolve a negative index now, unless it points before the
- beginning of the array, in which case record it for error
- reporting in magic_setdefelem. */
- elem < 0 && len + elem >= 0 ? len + elem : elem,
- 1));
+ /* Resolve a negative index that falls within the array. Leave
+ it negative it if falls outside the array. */
+ if (elem < 0 && len + elem >= 0)
+ elem = len + elem;
+ if (elem >= 0 && elem <= len)
+ /* Falls within the array. */
+ PUSHs(av_nonelem(av,elem));
+ else
+ /* Falls outside the array. If it is negative,
+ magic_setdefelem will use the index for error reporting.
+ */
+ mPUSHs(newSVavdefelem(av, elem, 1));
RETURN;
}
if (UNLIKELY(localizing)) {