develooper Front page | perl.perl5.porters | Postings from February 2015

[perl #123617] Segfault (stack overflow?) while fuzzing Perl 5.21.8

Thread Previous
From:
Father Chrysostomos via RT
Date:
February 1, 2015 15:54
Subject:
[perl #123617] Segfault (stack overflow?) while fuzzing Perl 5.21.8
Message ID:
rt-4.0.18-17520-1422806068-1573.123617-15-0@perl.org
On Sat Jan 24 22:44:36 2015, sprout wrote:
> On Sat Jan 24 22:08:15 2015, sprout wrote:
> > On Sat Jan 17 17:09:43 2015, hv wrote:
> > > A perl built with debugging gives:
> > >
> > > % ./perl test.pl
> > > perl: toke.c:2430: S_sublex_done: Assertion `(PL_parser-
> > > >lex_inwhat)
> > > == OP_SUBST || (PL_parser->lex_inwhat) == OP_TRANS' failed.
> > > Aborted (core dumped)
> > >  %
> > >
> > > Here's a shorter testcase (which doesn't clarify much):
> > >
> > > % cat test.pl
> > > "$a{m/""$b
> > > / m ss
> > > ";@c = split /x/
> > >  %
> > >
> > > We seem to have a PL_lex_repl with PL_lex_inwhat == OP_MATCH, which
> > > clearly
> > > can't happen.
> >
> > This is no doubt related to my two favourite japhs:
> >
> > s||${s/.*/|;
> > /s}Just another Perl hacker,
> > print
> >
> > "${;s/.*/Just an";
> > other Perl hacker,
> > /s} die or return;
> > print
> >
> > I don’t remember exactly how they work.  At the time I wrote them I
> > based them on the interesting implementation details I saw in toke.c,
> > which had something to do with PL_sublex_info.sub_inwhat.
> 
> skipspace() in toke.c, which is usually used to skip whitespace
> between tokens, reads more input from the file if it needs to.  But it
> checks first to see whether we are in a multiline construct and does
> not read more input if we are.
> 
> scan_str, which looks for the final delimiter of the string, does not
> check whether we are in a multiline construct, but just reads straight
> ahead.
> 
> So in this japh:
> 
> s||${s/.*/|;
> /s}Just another Perl hacker,
> print
> 
> When the replacement part of the outer s||| is parsed, ‘${s/.*/’ is
> the current ‘line’ of input, and scan_str, trying to find the final
> delimiter for the s///, reads the next line of input from the stream,
> which is ‘/s}Just another Perl hacker,’.  It finds its delimiter (and
> the /s flag to boot) immediately.  Then the inner s/// construct is
> exited via S_sublex_done, which sets PL_sublex_info.sub_inwhat to 0
> indiscriminately, even though we are still inside the outer string-
> like construct.
> 
> PL_sublex_info.sub_inwhat is what skipspace checks before reading more
> input.

The setting of PL_sublex_info.sub_inwhat to 0 prematurely does not appear to be involved in this particular case.

The current line of input, which is assumed to be the replacement part of the substitution, now contains ‘Just another Perl hacker,’, which is parsed as part of the s||...| and then parsing continues after that.

So

s||${s/.*/|;
/s}Just another Perl hacker,
print

ends up equivalent to

s||${s/.*/
/s}Just another Perl hacker,|;
print

(The purpose of that discourse was to refresh my memory of how this stuff works.)

Now, for the reduced crashing case:

"$a{m/""$b
/ m ss
";@c = split /x/

When parsing the initial "$a{m/" string, we find m/.../ inside it, and, again, scan_str reads the next line of input (‘/ m ss’), which is assumed to be inside the first string.

Notice that we have no } on the second line, so I assume the setting of sub_inwhat to 0 has some role here, but I do not yet see how PL_lex_repl gets set.  (The assertion fails because PL_lex_repl is set when we are inside a match op.)

-- 

Father Chrysostomos


---
via perlbug:  queue: perl5 status: open
https://rt.perl.org/Ticket/Display.html?id=123617

Thread Previous


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About