Make pp_splice handle nonexistent array elements
authorFather Chrysostomos <sprout@cpan.org>
Thu, 5 Sep 2013 21:39:47 +0000 (14:39 -0700)
committerFather Chrysostomos <sprout@cpan.org>
Fri, 6 Sep 2013 13:18:08 +0000 (06:18 -0700)
Commit ce0d59f changed AVs to use NULLs for nonexistent elements.

pp_splice needs to take that into account and avoid pushing NULLs on
to the stack.

pp.c
t/op/splice.t

diff --git a/pp.c b/pp.c
index a913ec0..6fc6c9f 100644 (file)
--- a/pp.c
+++ b/pp.c
@@ -4975,14 +4975,18 @@ PP(pp_splice)
 
        MARK = ORIGMARK + 1;
        if (GIMME == G_ARRAY) {                 /* copy return vals to stack */
+           const bool real = cBOOL(AvREAL(ary));
            MEXTEND(MARK, length);
-           Copy(AvARRAY(ary)+offset, MARK, length, SV*);
-           if (AvREAL(ary)) {
+           if (real)
                EXTEND_MORTAL(length);
-               for (i = length, dst = MARK; i; i--) {
+           for (i = 0, dst = MARK; i < length; i++) {
+               if ((*dst = AvARRAY(ary)[i+offset])) {
+                 if (real)
                    sv_2mortal(*dst);   /* free them eventually */
-                   dst++;
                }
+               else
+                   *dst = &PL_sv_undef;
+               dst++;
            }
            MARK += length - 1;
        }
@@ -5068,13 +5072,16 @@ PP(pp_splice)
        MARK = ORIGMARK + 1;
        if (GIMME == G_ARRAY) {                 /* copy return vals to stack */
            if (length) {
-               Copy(tmparyval, MARK, length, SV*);
-               if (AvREAL(ary)) {
+               const bool real = cBOOL(AvREAL(ary));
+               if (real)
                    EXTEND_MORTAL(length);
-                   for (i = length, dst = MARK; i; i--) {
+               for (i = 0, dst = MARK; i < length; i++) {
+                   if ((*dst = tmparyval[i])) {
+                     if (real)
                        sv_2mortal(*dst);       /* free them eventually */
-                       dst++;
                    }
+                   else *dst = &PL_sv_undef;
+                   dst++;
                }
            }
            MARK += length - 1;
index d462f0c..510d4cb 100644 (file)
@@ -92,4 +92,14 @@ ok( !oo->isa('Bar'), 'splice @ISA and make Foo a Bar');
 eval { splice( $new_arrayref, 0, 0, 1, 2, 3 ) };
 like($@, qr/Not an ARRAY/, 'undefined first argument to splice');
 
+# Test arrays with nonexistent elements (crashes when it fails)
+@a = ();
+$#a++;
+is sprintf("%s", splice @a, 0, 1), "",
+  'splice handles nonexistent elems when shrinking the array';
+@a = ();
+$#a++;
+is sprintf("%s", splice @a, 0, 1, undef), "",
+  'splice handles nonexistent elems when array len stays the same';
+
 done_testing;