This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
vivify array elements when putting them on stack
authorZefram <zefram@fysh.org>
Tue, 16 Jan 2018 06:22:17 +0000 (06:22 +0000)
committerZefram <zefram@fysh.org>
Tue, 16 Jan 2018 06:22:17 +0000 (06:22 +0000)
When the elements of an array are put on the stack, by a padav, rv2av,
or padrange op, null pointers in the AvARRAY were being pushed as
&PL_sv_undef, which was OK in rvalue contexts but caused misbehaviour
in lvalue contexts.  Change this to vivify these elements.  There's no
attempt here to limit the vivification to lvalue contexts: the existing
op flags aren't enough to detect \(@a), and attempting to catch all
cases where a new flag needs to be set would be an error-prone process.
Fixes [perl #8910].

pp_hot.c
t/op/array.t

index 8a74f58..d479ecf 100644 (file)
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -1163,15 +1163,17 @@ S_pushav(pTHX_ AV* const av)
     if (UNLIKELY(SvRMAGICAL(av))) {
         PADOFFSET i;
         for (i=0; i < (PADOFFSET)maxarg; i++) {
-            SV ** const svp = av_fetch(av, i, FALSE);
+            SV ** const svp = av_fetch(av, i, TRUE);
             SP[i+1] = svp ? *svp : &PL_sv_undef;
         }
     }
     else {
         PADOFFSET i;
         for (i=0; i < (PADOFFSET)maxarg; i++) {
-            SV * const sv = AvARRAY(av)[i];
-            SP[i+1] = LIKELY(sv) ? sv : &PL_sv_undef;
+            SV *sv = AvARRAY(av)[i];
+           if (!LIKELY(sv))
+               AvARRAY(av)[i] = sv = newSV(0);
+           SP[i+1] = sv;
         }
     }
     SP += maxarg;
index 59ba434..4d16272 100644 (file)
@@ -6,7 +6,7 @@ BEGIN {
     set_up_inc('.', '../lib');
 }
 
-plan (173);
+plan (178);
 
 #
 # @foo, @bar, and @ary are also used from tie-stdarray after tie-ing them
@@ -575,4 +575,20 @@ $#a = -1; $#a++;
 $#a = -1; $#a++;
 () = 0+splice @a, 0, 1, 1, 1;
 
+# [perl #8910] lazy creation of array elements used to leak out
+{
+    sub t8910 { $_[1] = 5; $_[2] = 7; }
+    my @p;
+    $p[0] = 1;
+    $p[2] = 2;
+    t8910(@p);
+    is "@p", "1 5 7", "lazy element creation with sub call";
+    my @q;
+    @q[0] = 1;
+    @q[2] = 2;
+    my @qr = \(@q);
+    is $qr[$_], \$q[$_], "lazy element creation with refgen" foreach 0..2;
+    isnt $qr[1], \undef, "lazy element creation with refgen";
+}
+
 "We're included by lib/Tie/Array/std.t so we need to return something true";