# HG changeset patch # User hannesw # Date 1507908312 -7200 # Node ID 079a87f875189dfe776af99e531e82ec59063331 # Parent 6694369ed3f941609050042becb7b64630bf81b5 8027302: Identifiers containing unicode escapes are not recognized as reserved words Reviewed-by: jlaskey, sundar diff -r 6694369ed3f9 -r 079a87f87518 src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IdentNode.java --- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IdentNode.java Fri Oct 13 15:22:02 2017 +0200 +++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IdentNode.java Fri Oct 13 17:25:12 2017 +0200 @@ -477,4 +477,14 @@ public IdentNode setIsDestructuredParameter() { return new IdentNode(this, name, type, flags | DESTRUCTURED_PARAMETER, programPoint, conversion); } + + /** + * Checks whether the source code for this ident contains a unicode escape sequence by comparing + * the length of its name with its length in source code. + * + * @return true if ident source contains a unicode escape sequence + */ + public boolean containsEscapes() { + return Token.descLength(getToken()) != name.length(); + } } diff -r 6694369ed3f9 -r 079a87f87518 src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java --- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java Fri Oct 13 15:22:02 2017 +0200 +++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java Fri Oct 13 17:25:12 2017 +0200 @@ -786,15 +786,9 @@ if (ch0 == '\\' && ch1 == 'u') { skip(2); final int ch = hexSequence(4, TokenType.IDENT); - if (isWhitespace((char)ch)) { - return null; - } - if (ch < 0) { - sb.append('\\'); - sb.append('u'); - } else { - sb.append((char)ch); - } + assert ! isWhitespace((char)ch); + assert ch >= 0; + sb.append((char)ch); } else { // Add regular character. sb.append(ch0); @@ -994,9 +988,6 @@ if (ch0 == '\\') { type = ESCSTRING; skip(1); - if (! isEscapeCharacter(ch0)) { - error(Lexer.message("invalid.escape.char"), STRING, position, limit); - } if (isEOL(ch0)) { // Multiline string literal skipEOL(false); @@ -1093,9 +1084,6 @@ } else if (ch0 == '\\') { skip(1); // EscapeSequence - if (!isEscapeCharacter(ch0)) { - error(Lexer.message("invalid.escape.char"), TEMPLATE, position, limit); - } if (isEOL(ch0)) { // LineContinuation skipEOL(false); @@ -1115,16 +1103,6 @@ } /** - * Is the given character a valid escape char after "\" ? - * - * @param ch character to be checked - * @return if the given character is valid after "\" - */ - protected boolean isEscapeCharacter(final char ch) { - return true; - } - - /** * Convert string to number. * * @param valueString String to convert. diff -r 6694369ed3f9 -r 079a87f87518 src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java --- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java Fri Oct 13 15:22:02 2017 +0200 +++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java Fri Oct 13 17:25:12 2017 +0200 @@ -1472,12 +1472,7 @@ */ private void verifyIdent(final IdentNode ident, final String contextString) { verifyStrictIdent(ident, contextString); - if (isES6()) { - final TokenType tokenType = TokenLookup.lookupKeyword(ident.getName().toCharArray(), 0, ident.getName().length()); - if (tokenType != IDENT && tokenType.getKind() != TokenKind.FUTURESTRICT) { - throw error(expectMessage(IDENT)); - } - } + checkEscapedKeyword(ident); } /** @@ -1502,6 +1497,18 @@ } } + /** + * ES6 11.6.2: A code point in a ReservedWord cannot be expressed by a | UnicodeEscapeSequence. + */ + private void checkEscapedKeyword(final IdentNode ident) { + if (isES6() && ident.containsEscapes()) { + final TokenType tokenType = TokenLookup.lookupKeyword(ident.getName().toCharArray(), 0, ident.getName().length()); + if (tokenType != IDENT && !(tokenType.getKind() == TokenKind.FUTURESTRICT && !isStrictMode)) { + throw error(AbstractParser.message("keyword.escaped.character"), ident.getToken()); + } + } + } + /* * VariableStatement : * var VariableDeclarationList ; @@ -2646,7 +2653,7 @@ }); } else { // ECMA 12.4.1 strict mode restrictions - verifyStrictIdent((IdentNode) exception, "catch argument"); + verifyIdent((IdentNode) exception, "catch argument"); } @@ -2761,6 +2768,7 @@ break; } detectSpecialProperty(ident); + checkEscapedKeyword(ident); return ident; case OCTAL_LEGACY: if (isStrictMode) { @@ -3404,6 +3412,7 @@ // Catch special functions. if (lhs instanceof IdentNode) { detectSpecialFunction((IdentNode)lhs); + checkEscapedKeyword((IdentNode)lhs); } lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false); @@ -3779,7 +3788,7 @@ expect(IDENT); } name = getIdent(); - verifyStrictIdent(name, "function name"); + verifyIdent(name, "function name"); } else if (isStatement) { // Nashorn extension: anonymous function statements. // Do not allow anonymous function statement if extensions @@ -4871,7 +4880,7 @@ final String contextString = "function parameter"; if (param instanceof IdentNode) { final IdentNode ident = (IdentNode)param; - verifyStrictIdent(ident, contextString); + verifyIdent(ident, contextString); final ParserContextFunctionNode currentFunction = lc.getCurrentFunction(); if (currentFunction != null) { currentFunction.addParameterBinding(ident); diff -r 6694369ed3f9 -r 079a87f87518 src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties --- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties Fri Oct 13 15:22:02 2017 +0200 +++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties Fri Oct 13 17:25:12 2017 +0200 @@ -62,6 +62,7 @@ parser.error.trailing.comma.in.json=Trailing comma is not allowed in JSON parser.error.missing.const.assignment=Missing assignment to constant "{0}" parser.error.unterminated.template.expression=Expected } after expression in template literal +parser.error.keyword.escaped.character=Keyword must not contain escaped characters # ES6 mode error messages parser.error.multiple.constructors=Class contains more than one constructor diff -r 6694369ed3f9 -r 079a87f87518 test/nashorn/script/basic/JDK-8027302.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/nashorn/script/basic/JDK-8027302.js Fri Oct 13 17:25:12 2017 +0200 @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2017, 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-8027302: Identifiers containing unicode escapes are not recognized as reserved words + * + * @test + * @run + */ + +// keywords containing escapes + +try { + eval("v\\u0061r i;"); + fail("Expected error"); +} catch (e) { + Assert.assertTrue(e instanceof SyntaxError); +} + +try { + eval("\\u0069f (true) ;"); + fail("Expected error"); +} catch (e) { + Assert.assertTrue(e instanceof ReferenceError); // no SyntaxError in ES5 +} + +try { + eval("if (true) ; \\u0065lse ;"); + fail("Expected error"); +} catch (e) { + Assert.assertTrue(e instanceof ReferenceError); // no SyntaxError in ES5 +} + +try { + eval("f\\u0075nction x() {}"); + fail("Expected error"); +} catch (e) { + Assert.assertTrue(e instanceof SyntaxError); +} + +try { + eval("var f = f\\u0075nction() {}"); + fail("Expected error"); +} catch (e) { + Assert.assertTrue(e instanceof SyntaxError); +} + +try { + eval("var o = { f: f\\u0075nction() {}}"); + fail("Expected error"); +} catch (e) { + Assert.assertTrue(e instanceof SyntaxError); +} + +try { + eval("var a = [f\\u0075nction() {}]"); + fail("Expected error"); +} catch (e) { + Assert.assertTrue(e instanceof SyntaxError); +} + +// keywords as identifiers, with and without escapes + +try { + eval("function break() {}"); + fail("Expected error"); +} catch (e) { + Assert.assertTrue(e instanceof SyntaxError); +} + +try { + eval("function bre\\u0061k() {}"); +} catch (e) { + fail("Unexpected error"); +} + +try { + eval("function f(break) {}"); + fail("Expected error"); +} catch (e) { + Assert.assertTrue(e instanceof SyntaxError); +} + +try { + eval("function f(bre\\u0061k) {}"); +} catch (e) { + fail("Unexpected error"); +} + +try { + eval("var break = 3"); + fail("Expected error"); +} catch (e) { + Assert.assertTrue(e instanceof SyntaxError); +} + +try { + eval("'use strict'; var break = 3"); + fail("Expected error"); +} catch (e) { + Assert.assertTrue(e instanceof SyntaxError); +} + +try { + eval("var bre\\u0061k = 3"); +} catch (e) { + fail("Unexpected error"); +} + +try { + eval("'use strict'; var bre\\u0061k = 3"); +} catch (e) { + fail("Unexpected error"); +} + +try { + eval("var package = 3"); +} catch (e) { + fail("Unexpected error"); +} + +try { + eval("'use strict'; var package = 3"); + fail("Expected error"); +} catch (e) { + Assert.assertTrue(e instanceof SyntaxError); +} + +try { + eval("var p\\u0061ckage = 3"); +} catch (e) { + fail("Unexpected error"); +} + +try { + eval("'use strict'; var p\\u0061ckage = 3"); +} catch (e) { + fail("Unexpected error"); +} + diff -r 6694369ed3f9 -r 079a87f87518 test/nashorn/script/basic/es6/JDK-8027302.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/nashorn/script/basic/es6/JDK-8027302.js Fri Oct 13 17:25:12 2017 +0200 @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2017, 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-8027302: Identifiers containing unicode escapes are not recognized as reserved words + * + * @test + * @run + * @option --language=es6 + */ + +// keywords containing escapes + +try { + eval("v\\u0061r i;"); + fail("Expected error"); +} catch (e) { + Assert.assertTrue(e instanceof SyntaxError); +} + +try { + eval("\\u0069f (true) ;"); + fail("Expected error"); +} catch (e) { + Assert.assertTrue(e instanceof SyntaxError); +} + +try { + eval("if (true) ; \\u0065lse ;"); + fail("Expected error"); +} catch (e) { + Assert.assertTrue(e instanceof SyntaxError); +} + +try { + eval("f\\u0075nction x() {}"); + fail("Expected error"); +} catch (e) { + Assert.assertTrue(e instanceof SyntaxError); +} + +try { + eval("var f = f\\u0075nction() {}"); + fail("Expected error"); +} catch (e) { + Assert.assertTrue(e instanceof SyntaxError); +} + +try { + eval("var o = { f: f\\u0075nction() {}}"); + fail("Expected error"); +} catch (e) { + Assert.assertTrue(e instanceof SyntaxError); +} + +try { + eval("var a = [f\\u0075nction() {}]"); + fail("Expected error"); +} catch (e) { + Assert.assertTrue(e instanceof SyntaxError); +} + +// keywords as identifiers, with and without escapes + +try { + eval("function break() {}"); + fail("Expected error"); +} catch (e) { + Assert.assertTrue(e instanceof SyntaxError); +} + +try { + eval("function bre\\u0061k() {}"); + fail("Expected error"); +} catch (e) { + Assert.assertTrue(e instanceof SyntaxError); +} + +try { + eval("function f(break) {}"); + fail("Expected error"); +} catch (e) { + Assert.assertTrue(e instanceof SyntaxError); +} + +try { + eval("function f(bre\\u0061k) {}"); + fail("Expected error"); +} catch (e) { + Assert.assertTrue(e instanceof SyntaxError); +} + +try { + eval("var break = 3"); + fail("Expected error"); +} catch (e) { + Assert.assertTrue(e instanceof SyntaxError); +} + +try { + eval("'use strict'; var break = 3"); + fail("Expected error"); +} catch (e) { + Assert.assertTrue(e instanceof SyntaxError); +} + +try { + eval("var bre\\u0061k = 3"); + fail("Expected error"); +} catch (e) { + Assert.assertTrue(e instanceof SyntaxError); +} + +try { + eval("'use strict'; var bre\\u0061k = 3"); + fail("Expected error"); +} catch (e) { + Assert.assertTrue(e instanceof SyntaxError); +} + +try { + eval("var package = 3"); +} catch (e) { + fail("Unexpected error"); +} + +try { + eval("'use strict'; var package = 3"); + fail("Expected error"); +} catch (e) { + Assert.assertTrue(e instanceof SyntaxError); +} + +try { + eval("var p\\u0061ckage = 3"); +} catch (e) { + fail("Unexpected error"); +} + +try { + eval("'use strict'; var p\\u0061ckage = 3"); + fail("Expected error"); +} catch (e) { + Assert.assertTrue(e instanceof SyntaxError); +} +