Arrow function followed by divide or syntax error?
Le 23 mai 2017 à 16:34, Gareth Heyes <gareth.heyes at portswigger.net> a écrit :
Hi all
I'd like to discuss this:-
x=x=>{}/alert(1)/+alert(2)// alerts on edge, syntax error on other browsers
So on Edge it results in two alerts but every other browser it's a syntax error. Personally I think Edge is right here because it's a function expression so why can't you use divide after.
This is not specific to the divide operator. If you try:
x => {} * alert(1)
you'll get a SyntaxError in all browsers but Edge, which interprets it as (x => {}) * alert(1)
.
Given how confusing that expression is, I think that the SyntaxError is the right choice.
x=>{} /alert(1)/+alert(2)//alerts twice on edge, once on other browsers
This follows from the ASI rules: non-Edge browsers add a missing semicolon between the two lines, because otherwise it would be a syntax error for them.
On 23 May 2017 at 17:01, Claude Pache <claude.pache at gmail.com> wrote:
This is not specific to the divide operator. If you try:
x => {} * alert(1)
Yeah of course I mentioned divide because it's more interesting because it can lead to js sandbox escapes.
you'll get a SyntaxError in all browsers but Edge, which interprets it as
(x => {}) * alert(1)
.Given how confusing that expression is, I think that the SyntaxError is the right choice.
Well it is a function expression. So IMO Edge is right. It's equivalent to: x=function(){} * alert(1)
On 24 May 2017 at 08:57, Gareth Heyes <gareth.heyes at portswigger.net> wrote:
you'll get a SyntaxError in all browsers but Edge, which interprets it as
(x => {}) * alert(1)
.Given how confusing that expression is, I think that the SyntaxError is the right choice.
Well it is a function expression. So IMO Edge is right. It's equivalent to: x=function(){} * alert(1)
Edge is wrong. Unlike an ordinary function expression, which is a
PrimaryExpression, an arrow function is merely an AssigmentExpression, so
has much lower precedence than any arithmetic operator. The rationale is
that its body doesn't necessarily have braces, so x => x * 1
would be
ambiguous.
Unlike an ordinary function expression, which is a PrimaryExpression, an arrow function is merely an AssigmentExpression, so has much lower precedence than any arithmetic operator.
I'm curious how this should be parsed so let's break this down.
Given the following "Script" (I don't think the actual goal matters much here):
x=x=>{}/alert(1)/+alert(2)//
Script : ScriptBody opt
ScriptBody : StatementList
StatementList [Yield, Return] : StatementListItem [?Yield, ?Return] StatementList [?Yield, ?Return] StatementListItem [?Yield, ?Return]
StatementListItem [Yield, Return] : Statement [?Yield, ?Return] Declaration [?Yield]
Statement [Yield, Return] : BlockStatement [?Yield, ?Return] VariableStatement [?Yield] EmptyStatement ExpressionStatement [?Yield] ... (trunced)
ExpressionStatement [Yield] : [lookahead ∉ { { , function , class , let [ }] Expression [In, ?Yield] ;
Expression [In, Yield] : AssignmentExpression [?In, ?Yield] Expression [?In, ?Yield] , AssignmentExpression [?In, ?Yield]
AssignmentExpression [In, Yield] : ConditionalExpression [?In, ?Yield] [+Yield] YieldExpression [?In] ArrowFunction [?In, ?Yield]LeftHandSideExpression [?Yield] = AssignmentExpression [?In, ?Yield] LeftHandSideExpression [?Yield] AssignmentOperator AssignmentExpression [?In, ?Yield]
I hope we can agree that the leading x=
is consumed by
"LeftHandSideExpression [?Yield] AssignmentOperator" in the very last
rule above. Proceeding with "AssignmentExpression" from the arrow arg.
Note that there is no other rule that applies up to this point.
ArrowFunction [In, Yield] : ArrowParameters [?Yield] [no LineTerminator here] => ConciseBody [?In]
ArrowParameters [Yield] : BindingIdentifier [?Yield] CoverParenthesizedExpressionAndArrowParameterList [?Yield]
Here "CoverParenthesizedExpressionAndArrowParameterList" will consume
the second x
and then the only rule in "ArrowFunction" will consume
the arrow (=>
). Continueing to parse the remainder
{}/alert(1)/+alert(2)//
starting at "ConciseBody".
ConciseBody [In] : [lookahead ≠ {] AssignmentExpression [?In] { FunctionBody }
Obviously only the second rule applies so we parse the function body
and the curlies. We parse greedy but the function body is empty so
only the next two chars are consumed ({}
). Parser has
/alert(1)/+alert(2)//
left to parse and the "Statement" rule has
depleted it's options. So we go back to "StatementList" and parse
another statement. This should result in a regular expression, a plus
operator, a call expression, and a single line comment.
I don't think there's a rule here that allows parsing operators after an explicit arrow function body as being part of the arrow function. In fact, I remember that this was explicitly designed this way to prevent this ambiguity. Beyond that I agree that it parses similar to function expressions.
If this was wrong I'd love to know the right way to parse this.
Note that the arrow function can only form an ExpressionStatement, which
requires a terminating semicolon. There is none in this example, nor a line
break that would allow one to be inserted implicitly. So when reaching the
first /
a syntax error is apparent, since there is no way the input can
still form a well-formed statement at that point.
Oh, so subtle. You're right, the missing semi makes it a syntax error. Thanks for clearing that up :)
I have filled an issue for Babylon babel/babylon#536.
x=x=>{}/alert(1)/+alert(2)// is a syntax error. We deliberately specified
it that way in the standard for the precedence reasons stated earlier in the thread.
Brian Terlson is filing a bug as we speak.
Waldemar
I'd like to discuss this:-
x=x=>{}/alert(1)/+alert(2)// alerts on edge, syntax error on other browsers
So on Edge it results in two alerts but every other browser it's a syntax error. Personally I think Edge is right here because it's a function expression so why can't you use divide after.
x=>{} /alert(1)/+alert(2)//alerts twice on edge, once on other browsers