Changeset 202828 in webkit


Ignore:
Timestamp:
Jul 5, 2016 1:05:02 PM (8 years ago)
Author:
sbarati@apple.com
Message:

our parsing for "use strict" is wrong when we first parse other directives that are not "use strict" but are located in a place where "use strict" would be valid
https://bugs.webkit.org/show_bug.cgi?id=159376
<rdar://problem/27108773>

Reviewed by Benjamin Poulain.

Our strict mode detection algorithm used to break if we ever saw a directive
that is not "use strict" but is syntactically located in a location where our
parser looks for "use strict". It broke as follows:

If a function started with a non "use strict" string literal, we will allow
"use strict" to be in any arbitrary statement inside the top level block in
the function body. For example, this meant that if we parsed a sequence of string
literals, followed by arbitrary statements, followed by "use strict", we would parse
the function as if it's in strict mode. This is the wrong behavior with respect to
the spec. This has consequences in other ways that break invariants of the language.
For example, we used to allow functions that are lexically nested inside what we deemed
a strict function to be non-strict. This used to fire an assertion if we ever skipped over
that function using the source provider cache, but it worked just fine in release builds.

This patch fixes this bug.

  • parser/Parser.cpp:

(JSC::Parser<LexerType>::parseSourceElements):
(JSC::Parser<LexerType>::parseStatement):

  • tests/stress/ensure-proper-strict-mode-parsing.js: Added.

(foo.bar):
(foo):
(bar.foo):
(bar):
(bar.call.undefined.this.throw.new.Error.string_appeared_here.baz):
(baz.call.undefined.undefined.throw.new.Error.string_appeared_here.jaz):
(jaz.call.undefined.this.throw.new.Error.string_appeared_here.vaz):

Location:
trunk/Source/JavaScriptCore
Files:
1 added
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r202827 r202828  
     12016-07-05  Saam Barati  <sbarati@apple.com>
     2
     3        our parsing for "use strict" is wrong when we first parse other directives that are not "use strict" but are located in a place where "use strict" would be valid
     4        https://bugs.webkit.org/show_bug.cgi?id=159376
     5        <rdar://problem/27108773>
     6
     7        Reviewed by Benjamin Poulain.
     8
     9        Our strict mode detection algorithm used to break if we ever saw a directive
     10        that is not "use strict" but is syntactically located in a location where our
     11        parser looks for "use strict". It broke as follows:
     12
     13        If a function started with a non "use strict" string literal, we will allow
     14        "use strict" to be in any arbitrary statement inside the top level block in
     15        the function body. For example, this meant that if we parsed a sequence of string
     16        literals, followed by arbitrary statements, followed by "use strict", we would parse
     17        the function as if it's in strict mode. This is the wrong behavior with respect to
     18        the spec. This has consequences in other ways that break invariants of the language.
     19        For example, we used to allow functions that are lexically nested inside what we deemed
     20        a strict function to be non-strict. This used to fire an assertion if we ever skipped over
     21        that function using the source provider cache, but it worked just fine in release builds.
     22
     23        This patch fixes this bug.
     24
     25        * parser/Parser.cpp:
     26        (JSC::Parser<LexerType>::parseSourceElements):
     27        (JSC::Parser<LexerType>::parseStatement):
     28        * tests/stress/ensure-proper-strict-mode-parsing.js: Added.
     29        (foo.bar):
     30        (foo):
     31        (bar.foo):
     32        (bar):
     33        (bar.call.undefined.this.throw.new.Error.string_appeared_here.baz):
     34        (baz.call.undefined.undefined.throw.new.Error.string_appeared_here.jaz):
     35        (jaz.call.undefined.this.throw.new.Error.string_appeared_here.vaz):
     36
    1372016-07-05  Saam Barati  <sbarati@apple.com>
    238
  • trunk/Source/JavaScriptCore/parser/Parser.cpp

    r202648 r202828  
    398398    const unsigned lengthOfUseStrictLiteral = 12; // "use strict".length
    399399    TreeSourceElements sourceElements = context.createSourceElements();
    400     bool seenNonDirective = false;
    401400    const Identifier* directive = 0;
    402401    unsigned directiveLiteralLength = 0;
    403402    auto savePoint = createSavePoint();
    404     bool hasSetStrict = false;
     403    bool shouldCheckForUseStrict = mode == CheckForStrictMode;
    405404   
    406405    while (TreeStatement statement = parseStatementListItem(context, directive, &directiveLiteralLength)) {
    407         if (mode == CheckForStrictMode && !seenNonDirective) {
     406        if (shouldCheckForUseStrict) {
    408407            if (directive) {
    409408                // "use strict" must be the exact literal without escape sequences or line continuation.
    410                 if (!hasSetStrict && directiveLiteralLength == lengthOfUseStrictLiteral && m_vm->propertyNames->useStrictIdentifier == *directive) {
     409                if (directiveLiteralLength == lengthOfUseStrictLiteral && m_vm->propertyNames->useStrictIdentifier == *directive) {
    411410                    setStrictMode();
    412                     hasSetStrict = true;
     411                    shouldCheckForUseStrict = false; // We saw "use strict", there is no need to keep checking for it.
    413412                    if (!isValidStrictMode()) {
    414413                        if (m_parserState.lastFunctionName) {
     
    429428                    continue;
    430429                }
    431             } else
    432                 seenNonDirective = true;
     430
     431                // We saw a directive, but it wasn't "use strict". We reset our state to
     432                // see if the next statement we parse is also a directive.
     433                directive = nullptr;
     434            } else {
     435                // We saw a statement that wasn't in the form of a directive. The spec says that "use strict"
     436                // is only allowed as the first statement, or after a sequence of directives before it, but
     437                // not after non-directive statements.
     438                shouldCheckForUseStrict = false;
     439            }
    433440        }
    434441        context.appendStatement(sourceElements, statement);
     
    16021609    DepthManager statementDepth(&m_statementDepth);
    16031610    m_statementDepth++;
    1604     directive = 0;
    16051611    int nonTrivialExpressionCount = 0;
    16061612    failIfStackOverflow();
     
    17211727        TreeStatement exprStatement = parseExpressionStatement(context);
    17221728        if (directive && nonTrivialExpressionCount != m_parserState.nonTrivialExpressionCount)
    1723             directive = 0;
     1729            directive = nullptr;
    17241730        result = exprStatement;
    17251731        break;
Note: See TracChangeset for help on using the changeset viewer.