diff options
author | Tony Cook <tony@develop-help.com> | 2017-07-25 14:36:28 +1000 |
---|---|---|
committer | Tony Cook <tony@develop-help.com> | 2017-09-19 10:55:23 +1000 |
commit | 08ccc81012771c7ca6dc701881d86876ceb40e54 (patch) | |
tree | 2da35c0b4acc211651d1ae31c75dfc87a0ec5f05 /toke.c | |
parent | 570a6dbb8c57e331a0496105a6acdc1f06e03496 (diff) | |
download | perl-08ccc81012771c7ca6dc701881d86876ceb40e54.tar.gz |
(perl #131777) prevent non-'=' assign ops tokens in sub signatures
The yacc grammar introduced in d3d9da4a7 uses ASSIGNOP to
represent the '=' used to introduce default values in subroutine
signatures, unfortunately the parser returns ASSIGNOP for non-simple
assignments, which allowed:
sub foo ($x += 1) { ... }
to default $x to 1.
Modify yylex to accept only the simple assignment operator after a
subroutine parameter.
I'm not especially happy with the error recovery here.
Diffstat (limited to 'toke.c')
-rw-r--r-- | toke.c | 37 |
1 files changed, 34 insertions, 3 deletions
@@ -5125,12 +5125,43 @@ Perl_yylex(pTHX) 0, cBOOL(UTF), FALSE); *dest = '\0'; assert(PL_tokenbuf[1]); /* we have a variable name */ + } + else { + *PL_tokenbuf = 0; + PL_in_my = 0; + } + + s = skipspace(s); + /* parse the = for the default ourselves to avoid '+=' etc being accepted here + * as the ASSIGNOP, and exclude other tokens that start with = + */ + if (*s == '=' && (!s[1] || strchr("=~>", s[1]) == 0)) { + /* save now to report with the same context as we did when + * all ASSIGNOPS were accepted */ + PL_oldbufptr = s; + + ++s; + NEXTVAL_NEXTTOKE.ival = 0; + force_next(ASSIGNOP); + PL_expect = XTERM; + } + else if (*s == ',' || *s == ')') { + PL_expect = XOPERATOR; + } + else { + /* make sure the context shows the unexpected character and + * hopefully a bit more */ + if (*s) ++s; + while (*s && *s != '$' && *s != '@' && *s != '%' && *s != ')') + s++; + PL_bufptr = s; /* for error reporting */ + yyerror("Illegal operator following parameter in a subroutine signature"); + PL_in_my = 0; + } + if (*PL_tokenbuf) { NEXTVAL_NEXTTOKE.ival = sigil; force_next('p'); /* force a signature pending identifier */ } - else - PL_in_my = 0; - PL_expect = XOPERATOR; break; case ')': |