8143304: Random failures when script size exceeds token limits
authorhannesw
Thu, 19 Nov 2015 14:37:14 +0100
changeset 33890 2e8c1be40a52
parent 33889 d12616b2b375
child 33891 2708ec4e47af
child 34445 2637e398e0a4
8143304: Random failures when script size exceeds token limits Reviewed-by: sundar, attila, lagergren
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/AbstractParser.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Token.java
nashorn/test/script/basic/JDK-8059934.js
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java	Thu Nov 19 11:28:34 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java	Thu Nov 19 14:37:14 2015 +0100
@@ -3323,9 +3323,6 @@
 
         if (needsScope) {
             method.loadCompilerConstant(SCOPE);
-        }
-
-        if (needsScope) {
             loadExpressionUnbounded(init);
             // block scoped variables need a DECLARE flag to signal end of temporal dead zone (TDZ)
             final int flags = getScopeCallSiteFlags(identSymbol) | (varNode.isBlockScoped() ? CALLSITE_DECLARE : 0);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/AbstractParser.java	Thu Nov 19 11:28:34 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/AbstractParser.java	Thu Nov 19 14:37:14 2015 +0100
@@ -103,6 +103,9 @@
      * @param lineOffset Offset from which lines should be counted
      */
     protected AbstractParser(final Source source, final ErrorManager errors, final boolean strict, final int lineOffset) {
+        if (source.getLength() > Token.LENGTH_MASK) {
+            throw new RuntimeException("Source exceeds size limit of " + Token.LENGTH_MASK + " bytes");
+        }
         this.source       = source;
         this.errors       = errors;
         this.k            = -1;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java	Thu Nov 19 11:28:34 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java	Thu Nov 19 14:37:14 2015 +0100
@@ -213,7 +213,6 @@
      * function body. This is used with the feature where the parser is skipping nested function bodies to
      * avoid reading ahead unnecessarily when we skip the function bodies.
      */
-
     public Lexer(final Source source, final int start, final int len, final TokenStream stream, final boolean scripting, final boolean es6, final boolean pauseOnFunctionBody) {
         super(source.getContent(), 1, start, len);
         this.source      = source;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Token.java	Thu Nov 19 11:28:34 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Token.java	Thu Nov 19 14:37:14 2015 +0100
@@ -30,11 +30,21 @@
 import jdk.nashorn.internal.runtime.Source;
 
 /**
- * Basic parse/lex unit.
- *
+ * A token is a 64 bit long value that represents a basic parse/lex unit.
+ * This class provides static methods to manipulate lexer tokens.
  */
 public class Token {
 
+    /**
+     * We use 28 bits for the position and 28 bits for the length of the token.
+     * This limits the maximal length of code we can handle to 2 ^ 28 - 1 bytes.
+     */
+    public final static int LENGTH_MASK = 0xfffffff;
+
+    // The first 8 bits are used for the token type, followed by length and position
+    private final static int LENGTH_SHIFT = 8;
+    private final static int POSITION_SHIFT  = 36;
+
     private Token() {
     }
 
@@ -46,8 +56,9 @@
      * @return Token descriptor.
      */
     public static long toDesc(final TokenType type, final int position, final int length) {
-        return (long)position << 32 |
-               (long)length   << 8  |
+        assert position <= LENGTH_MASK && length <= LENGTH_MASK;
+        return (long)position << POSITION_SHIFT |
+               (long)length   << LENGTH_SHIFT  |
                type.ordinal();
     }
 
@@ -57,7 +68,7 @@
      * @return Start position of the token in the source.
      */
     public static int descPosition(final long token) {
-        return (int)(token >>> 32);
+        return (int)(token >>> POSITION_SHIFT);
     }
 
     /**
@@ -98,7 +109,7 @@
      * @return Length of the token.
      */
     public static int descLength(final long token) {
-        return (int)token >>> 8;
+        return (int)((token >>> LENGTH_SHIFT) & LENGTH_MASK);
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8059934.js	Thu Nov 19 14:37:14 2015 +0100
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8059934: Random failures when script size exceeds token limits
+ *
+ * @test
+ * @run
+ */
+
+// Make sure that we can successfully evaluate a 100 MB string.
+// We don't go beyond that as we'd likely hit heap size limits.
+var src = "var x = 'ok';";
+for (var i = 0; i < 1000000; i++) {
+    src += "                                                                                                    ";
+}
+src += "x;";
+
+Assert.assertEquals(100000015, src.length);
+Assert.assertEquals("ok", eval(src));
+