This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
[perl #123763] Clear target on my $_; split
authorFather Chrysostomos <sprout@cpan.org>
Sun, 1 Mar 2015 06:31:25 +0000 (22:31 -0800)
committerFather Chrysostomos <sprout@cpan.org>
Sun, 1 Mar 2015 06:31:25 +0000 (22:31 -0800)
If a lexical $_ is in scope, then the first argument to split, which
starts out as a match op, will get the pad offset of $_ as its target,
since that’s how implicit lexical $_=~ usually works.

ck_split changes that first argument to a pushre op.  The target
was not being cleared.  That did not cause any problems, until
v5.21.4-408-gfd017c0, which optimised lexical @array = split to write
to split @array directly, by storing making lexical array’s pad offset
the pushre’s target.

You can see the obvious conflict there.  We end up trying to split to
$_, which is not an array.  On a debugging build, you get an assertion
failure when trying to extend $_.  Make the split list long enough,
and you get a crash on non-debugging builds.

debugging$ ./miniperl -e 'my $_; split'
Use of my $_ is experimental at -e line 1.
Assertion failed: (SvTYPE(av) == SVt_PVAV), function Perl_av_extend, file av.c, line 70.

non-debugging$ ./miniperl -e 'my $_; split //, "a"x100000'
Use of my $_ is experimental at -e line 1.
Segmentation fault: 11

op.c
t/base/lex.t

diff --git a/op.c b/op.c
index 073cb1b..45cde2b 100644 (file)
--- a/op.c
+++ b/op.c
@@ -11097,6 +11097,8 @@ Perl_ck_split(pTHX_ OP *o)
         op_sibling_splice(o, NULL, 0, kid);
     }
     CHANGE_TYPE(kid, OP_PUSHRE);
+    /* target implies @ary=..., so wipe it */
+    kid->op_targ = 0;
     scalar(kid);
     if (((PMOP *)kid)->op_pmflags & PMf_GLOBAL) {
       Perl_ck_warner(aTHX_ packWARN(WARN_REGEXP),
index 9a8cf14..fdeafb1 100644 (file)
@@ -502,4 +502,5 @@ eval q|s##[}#e|;
 {
  local $SIG{__WARN__}=sub{};
  eval q|my($_);0=split|;
+ eval q|my $_; @x = split|;
 }