Don’t use strchr when scanning for newline after <<foo
authorFather Chrysostomos <sprout@cpan.org>
Tue, 21 Aug 2012 01:06:41 +0000 (18:06 -0700)
committerFather Chrysostomos <sprout@cpan.org>
Tue, 21 Aug 2012 21:11:02 +0000 (14:11 -0700)
The code that uses this is specifically for parsing <<foo inside a
quote-like operator inside a string eval.

This prints bar:

eval "s//<<foo/e
bar
foo
";
print $_ || $@;

This prints Can't find string terminator blah blah blah:

eval "s//<<foo/e #\0
bar
foo
";
print $_ || $@;

Nulls in comments are allowed elsewhere.  This prints bar:

eval "\$_ = <<foo #\0
bar
foo
";
print $_ || $@;

The problem with strchr is that it is specifically for scanning null-
terminated strings.  If embedded nulls are permitted (and should be in
this case), memchr should be used.

This code was added by 0244c3a403.

t/base/lex.t
toke.c

index 559cc30..2baa5da 100644 (file)
@@ -1,6 +1,6 @@
 #!./perl
 
-print "1..59\n";
+print "1..60\n";
 
 $x = 'x';
 
@@ -288,3 +288,10 @@ END
 |e
 ';
 print $_ || "not ok 59\n";
+
+$_ = "";
+eval "s/(?:)/<<foo/e #\0
+ok 60 - null on same line as heredoc in s/// in eval
+foo
+";
+print $_ || "not ok 60\n";
diff --git a/toke.c b/toke.c
index 6b1a8ae..ab79394 100644 (file)
--- a/toke.c
+++ b/toke.c
@@ -9605,7 +9605,7 @@ S_scan_heredoc(pTHX_ register char *s)
        char * const bufend = SvEND(PL_sublex_info.super_linestr);
        char * const olds = s - SvCUR(herewas);
        term = *PL_tokenbuf;
-       s = strchr(bufptr, '\n');
+       s = (char *)memchr((void *)bufptr, '\n', bufend-bufptr);
        if (!s)
            s = bufend;
        d = s;