This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
(perl #129190) intuit_method() can move the line buffer
authorTony Cook <tony@develop-help.com>
Thu, 8 Sep 2016 03:21:02 +0000 (13:21 +1000)
committerTony Cook <tony@develop-help.com>
Tue, 24 Jan 2017 04:24:40 +0000 (15:24 +1100)
and broke PL_bufptr when it did.

t/op/lex.t
toke.c

index c8ecf36..7a05ee9 100644 (file)
@@ -7,7 +7,7 @@ use warnings;
 
 BEGIN { chdir 't' if -d 't'; require './test.pl'; }
 
-plan(tests => 35);
+plan(tests => 36);
 
 {
     no warnings 'deprecated';
@@ -285,3 +285,6 @@ EOM
     {},
     "[perl #129273] heap use after free or overflow"
 );
+
+fresh_perl_like('flock  _$', qr/Not enough arguments for flock/, {stderr => 1},
+                "[perl #129190] intuit_method() invalidates PL_bufptr");
diff --git a/toke.c b/toke.c
index ca06b7a..0e02fd5 100644 (file)
--- a/toke.c
+++ b/toke.c
@@ -4276,13 +4276,14 @@ S_intuit_method(pTHX_ char *start, SV *ioname, CV *cv)
     }
 
     if (*start == '$') {
+        SSize_t start_off = start - SvPVX(PL_linestr);
        if (cv || PL_last_lop_op == OP_PRINT || PL_last_lop_op == OP_SAY
             || isUPPER(*PL_tokenbuf))
            return 0;
         /* this could be $# */
         if (isSPACE(*s))
             s = skipspace(s);
-       PL_bufptr = start;
+       PL_bufptr = SvPVX(PL_linestr) + start_off;
        PL_expect = XREF;
        return *s == '(' ? FUNCMETH : METHOD;
     }
@@ -7262,17 +7263,24 @@ Perl_yylex(pTHX)
                                                                == OA_FILEREF))
                {
                    bool immediate_paren = *s == '(';
+                    SSize_t s_off;
 
                    /* (Now we can afford to cross potential line boundary.) */
                    s = skipspace(s);
 
+                    /* intuit_method() can indirectly call lex_next_chunk(),
+                     * invalidating s
+                     */
+                    s_off = s - SvPVX(PL_linestr);
                    /* Two barewords in a row may indicate method call. */
                    if (   (   isIDFIRST_lazy_if_safe(s, PL_bufend, UTF)
                             || *s == '$')
                         && (tmp = intuit_method(s, lex ? NULL : sv, cv)))
                     {
+                        /* the code at method: doesn't use s */
                        goto method;
                    }
+                    s = SvPVX(PL_linestr) + s_off;
 
                    /* If not a declared subroutine, it's an indirect object. */
                    /* (But it's an indir obj regardless for sort.) */