Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Strict Directive needs to be preflighted #149

Open
3cp opened this issue Oct 30, 2020 · 15 comments
Open

Use Strict Directive needs to be preflighted #149

3cp opened this issue Oct 30, 2020 · 15 comments
Labels
wontfix This will not be worked on

Comments

@3cp
Copy link
Member

3cp commented Oct 30, 2020

Found this issue while cleaning up test262 file, not sure if this is possible in meriyah.
It's not a serious bug in real world, as people always put use strict directive at beginning of a scope.

Meriyah rejects following code as per spec:

> parse('"use strict"; "\\1";')
Uncaught:
[ParseError [SyntaxError]: [1:16]: Octal escape sequences are not allowed in strict mode
] {
  index: 16,
  line: 1,
  column: 16,
  description: '[1:16]: Octal escape sequences are not allowed in strict mode',
  loc: { line: 1, column: 16 }
}

But failed to do so if the use strict directive is after the problematic code.

> parse('"\\1"; "use strict";')
{
  type: 'Program',
  sourceType: 'script',
  body: [
    { type: 'ExpressionStatement', expression: [Object] },
    { type: 'ExpressionStatement', expression: [Object] }
  ]
}
@KFlash
Copy link
Contributor

KFlash commented Oct 30, 2020

Should be an easy fix? What about using the mutual parser flag for this if in function body, and if on top level use a variable outside the loop.

@3cp
Copy link
Member Author

3cp commented Oct 30, 2020

I didn't follow. When passing "\1", how did you turn on strict mode from the token ("use strict") not parsed yet?

@KFlash
Copy link
Contributor

KFlash commented Oct 30, 2020

Give me 30 min to come up with a solution

@KFlash
Copy link
Contributor

KFlash commented Oct 30, 2020

It's an octal so you simply add a mutual parser flag in the number scanner and other places where octals occur. Note You need to reset that flag for each time you do the token dispatch. Soon as you have the mutual parser flag, try something like this

 let seenOctal = false;

  while (parser.token === Token.StringLiteral) {
    expr = parseLiteral(parser, context);
    // "use strict" must be the exact literal without escape sequences or line continuation.
    if ( VALID STRICT MODE CODE  {
      if (seenOctal === 1) // TODO! Throw an error
      context |= Context.Strict;
    } else {
      if (seenOctal  === 0 && (parser.flags & Flags.Octals) === Flags.Octals) {
        seenOctal  = 1; // We seen it, but no strict mode yet
      }
    }

// .... Rest of the code
  }

Note This can be tweaked for performance

Update I'm not even sure you would need the extra seenOctal . Maybe you can check the flag directly

@3cp
Copy link
Member Author

3cp commented Oct 30, 2020

It's not just octal, there are many other failures in strict mode need to be handled. Browser might re-parse the whole function scope when strict mode is changed at middle of the function scope.

@3cp
Copy link
Member Author

3cp commented Oct 30, 2020

I don't understand why ecma did not enforce directive to be only allowed at top of a function scope.

@KFlash
Copy link
Contributor

KFlash commented Oct 30, 2020

Open an ticket in the ECMA specs repo

@3cp
Copy link
Member Author

3cp commented Oct 31, 2020

Just noticed tenko did very well for this case.

And I found out bit more in nodejs

>  "\1";"use strict";
 "\1";"use strict";
   

Uncaught SyntaxError: Octal escape sequences are not allowed in strict mode.
>  "\1";1+1;"use strict";
'use strict'

You see, when "\1" and "use strict" are not adjacent, js parser did not complain. And tenko replicated this behavior 100%!

There must be something explicit in ecma spec...

BTW for reference, leading "use strict" is always in effect as we expected.

> "use strict"; 1+1; "\1";
"use strict"; 1+1; "\1";
                     

Uncaught SyntaxError: Octal escape sequences are not allowed in strict mode.

@KFlash
Copy link
Contributor

KFlash commented Oct 31, 2020

What about copy Tenko on that part? Not sure about the regex but..

@3cp
Copy link
Member Author

3cp commented Oct 31, 2020

I will try to decipher ecma spec first. That adjacency is weird.

@KFlash
Copy link
Contributor

KFlash commented Oct 31, 2020

In my own language (I invented a language similar to TS, but faster), I'm skipping WS first, and then I do the directive scanning with tons of bitmasks. That way I can add a diagnostic (throw an error) with bitmasks fiddling, and the issue you mentioned before is non-existing. I'm not even using the scanner code.

This because the entire code is structured as an optimized finite state machine. There is no concern of nested productions because I'm only validating strings (not even parsing them), aborting with everything else. And the validation will not happen unless a single or double quote has been seen (start of string literal).

After I reset to "normal state" and do the normal parsing.

@3cp
Copy link
Member Author

3cp commented Oct 31, 2020

> "\1";"use strict"
"\1";"use strict"
  

Uncaught SyntaxError: Octal escape sequences are not allowed in strict mode.
> var a = "\1";"use strict"
'use strict'

> var a = "\1";"use strict";"\1"
'\u0001'

The first case is due to "\1" is a directive. The two expression statements formed "A Directive Prologue" at beginning of list statements.

In the second case, "use strict" does NOT form "A Directive Prologue" because it's not from the beginning of the list statements.

The third case confirmed "use strict" has no effect if it's not in "A Directive Prologue".

In short, `"use strict" can appear in any location of the whole "A Directive Prologue", it can affect directives (string literal expression) before it.

ECMA did enforce the location of directives.

@KFlash
Copy link
Contributor

KFlash commented Nov 1, 2020

so, easy fix?

@3cp
Copy link
Member Author

3cp commented Nov 1, 2020

I am not going to try, at least for now.
This bug has no impact on real world code. It's just an edge case in the spec. People has no reason to write code like this, rather than testing a parser's spec compliance.

@3cp
Copy link
Member Author

3cp commented Nov 1, 2020

For record, the disabled test262 tests.

// FIXME: "use strict" should be preflighted
'147fa078a7436e0e.js',
'15a6123f6b825c38.js',
'3bc2b27a7430f818.js',

@3cp 3cp added the wontfix This will not be worked on label Dec 29, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
wontfix This will not be worked on
Projects
None yet
Development

No branches or pull requests

2 participants