This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
[perl #123995] Assert fail with s;@{<<;
authorFather Chrysostomos <sprout@cpan.org>
Wed, 18 Mar 2015 09:35:50 +0000 (02:35 -0700)
committerFather Chrysostomos <sprout@cpan.org>
Thu, 19 Mar 2015 05:20:37 +0000 (22:20 -0700)
If s;; gobbles up the implicit semicolon that is tacked on to the end
of the file, it can confuse the here-doc parser into thinking it is
inside a string eval, because there is no file handle.  We need to
check for that possibility where the assertion was failing.

t/op/lex.t
toke.c

index 8314f41..a4ce65c 100644 (file)
@@ -7,7 +7,7 @@ use warnings;
 
 BEGIN { chdir 't' if -d 't'; require './test.pl'; }
 
-plan(tests => 24);
+plan(tests => 25);
 
 {
     no warnings 'deprecated';
@@ -202,3 +202,10 @@ fresh_perl_is(
 
 is eval "qq'@\x{ff13}'", "\@\x{ff13}",
   '"@<fullwidth digit>" [perl #123963]';
+
+fresh_perl_is(
+  "s;\@{<<a;\n",
+  "Can't find string terminator \"a\" anywhere before EOF at - line 1.\n",
+   { stderr => 1 },
+  's;@{<<a; [perl #123995]'
+);
diff --git a/toke.c b/toke.c
index 414a03a..3b60488 100644 (file)
--- a/toke.c
+++ b/toke.c
@@ -9284,8 +9284,13 @@ S_scan_heredoc(pTHX_ char *s)
               lexing scope.  In a file, we will have broken out of the
               loop in the previous iteration.  In an eval, the string buf-
               fer ends with "\n;", so the while condition above will have
-              evaluated to false.  So shared can never be null. */
-           assert(shared);
+              evaluated to false.  So shared can never be null.  Or so you
+              might think.  Odd syntax errors like s;@{<<; can gobble up
+              the implicit semicolon at the end of a flie, causing the
+              file handle to be closed even when we are not in a string
+              eval.  So shared may be null in that case.  */
+           if (UNLIKELY(!shared))
+               goto interminable;
            /* A LEXSHARED struct with a null ls_prev pointer is the outer-
               most lexing scope.  In a file, shared->ls_linestr at that
               level is just one line, so there is no body to steal. */