This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Fix substitution in substitution pattern
authorFather Chrysostomos <sprout@cpan.org>
Tue, 21 Aug 2012 06:58:59 +0000 (23:58 -0700)
committerFather Chrysostomos <sprout@cpan.org>
Tue, 21 Aug 2012 21:11:03 +0000 (14:11 -0700)
commit7cc341114c4476436b593500ef63fa0925f746ca
tree79a58e29f5df8564fad98e4c24dbc90ef9c68e1e
parent99bd9d90ba5640856c6c421a174ea6e2743a4b3a
Fix substitution in substitution pattern

Guess what this prints:

s/${s|||, \""}Just another Perl hacker,
/anything/;
print

And look at this:

$ perl5.6.2 -e 's/${s|||;\""}/foo\n/; print;'
$ perl5.16.0 -e 's/${s|||;\""}/foo\n/; print;'
$ perl5.17.2 -e 's/${s|||;\""}/foo\n/; print;'
Bus error
$ ./miniperl -e 's/${s|||;\""}/foo\n/; print;'
Bus error

The first two gave no output, though they should have shown "foo".
And bleadperl now crashes.

When the lexer parses a quote-like operator, it begins by extracting
what is between the quotes.  It puts it in an SV stored in the varia-
ble PL_lex_stuff.  Then, if it is y/// or s///, it scans the replace-
ment part and puts it in an SV in PL_lex_repl.  When it finishes with
it, it sets PL_lex_repl to NULL.

Now, if you put s/// in the pattern part of s/// (or y in s), the
inner s/// will clobber PL_lex_repl with its own replacement string.
So, when the outer s/// finish parsing its pattern and wants its
replacement string.  If it is not there, it assumes it has already
parsed it (whether PL_lex_repl is set is how it remembers which half
of s/// it is parsing), and proceeds to feed bad code to the parser,
resulting in a bad op tree.

PL_lex_repl needs to be localised when a quote-like operator is
parsed.  Since localisation for quote-like operators happens in a sep-
arate yylex call (yylex calls sublex_push, which does it) after the
string delimiters are found, at which point PL_lex_repl has already
been set (clobbering the previous value), we change the delim-
iter-scanning code (scan_{str,trans,subst}) to use the new
PL_sublex_info.repl, which sublex_push now copies into PL_lex_repl
after localising the latter.
perl.h
t/base/lex.t
toke.c