# HG changeset patch # User sundar # Date 1413382803 -19800 # Node ID 2bf4c14345aa3ccc9b3281a728f216405ee14938 # Parent ef1e5e03e03e8e6e27ea3835358168df3ef44485 8060688: Nashorn: Generated script class name fails --verify-code for names with special chars Reviewed-by: jlaskey, hannesw diff -r ef1e5e03e03e -r 2bf4c14345aa src/jdk/nashorn/internal/codegen/Compiler.java --- a/src/jdk/nashorn/internal/codegen/Compiler.java Wed Oct 15 16:00:21 2014 +0200 +++ b/src/jdk/nashorn/internal/codegen/Compiler.java Wed Oct 15 19:50:03 2014 +0530 @@ -410,10 +410,29 @@ baseName = baseName + installer.getUniqueScriptId(); } - final String mangled = NameCodec.encode(baseName); + // ASM's bytecode verifier does not allow JVM allowed safe escapes using '\' as escape char. + // While ASM accepts such escapes for method names, field names, it enforces Java identifier + // for class names. Workaround that ASM bug here by replacing JVM 'dangerous' chars with '_' + // rather than safe encoding using '\'. + final String mangled = env._verify_code? replaceDangerChars(baseName) : NameCodec.encode(baseName); return mangled != null ? mangled : baseName; } + private static final String DANGEROUS_CHARS = "\\/.;:$[]<>"; + private static String replaceDangerChars(final String name) { + final int len = name.length(); + final StringBuilder buf = new StringBuilder(); + for (int i = 0; i < len; i++) { + final char ch = name.charAt(i); + if (DANGEROUS_CHARS.indexOf(ch) != -1) { + buf.append('_'); + } else { + buf.append(ch); + } + } + return buf.toString(); + } + private String firstCompileUnitName() { final StringBuilder sb = new StringBuilder(SCRIPTS_PACKAGE). append('/'). diff -r ef1e5e03e03e -r 2bf4c14345aa test/script/nosecurity/JDK-8060688.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/nosecurity/JDK-8060688.js Wed Oct 15 19:50:03 2014 +0530 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2014, 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-8060688: Nashorn: Generated script class name fails --verify-code for names with special chars + * + * @test + * @run + */ + +var NashornEngineFactory = Java.type("jdk.nashorn.api.scripting.NashornScriptEngineFactory"); +var ScriptEngine = Java.type("javax.script.ScriptEngine"); +var ScriptContext = Java.type("javax.script.ScriptContext"); + +var factory = new NashornEngineFactory(); + +var e = factory.getScriptEngine("--verify-code"); + +function evalAndCheck(code) { + try { + e.eval(code); + } catch (exp) { + exp.printStackTrace(); + } +} + +// check default name +evalAndCheck("var a = 3"); +// check few names with special chars +var scontext = e.context; +scontext.setAttribute(ScriptEngine.FILENAME, "", ScriptContext.ENGINE_SCOPE); +evalAndCheck("var h = 'hello'"); +scontext.setAttribute(ScriptEngine.FILENAME, "[myscript]", ScriptContext.ENGINE_SCOPE); +evalAndCheck("var foo = 'world'"); +scontext.setAttribute(ScriptEngine.FILENAME, ";/\\$.", ScriptContext.ENGINE_SCOPE); +evalAndCheck("var foo = 'helloworld'"); diff -r ef1e5e03e03e -r 2bf4c14345aa test/src/jdk/nashorn/internal/codegen/CompilerTest.java --- a/test/src/jdk/nashorn/internal/codegen/CompilerTest.java Wed Oct 15 16:00:21 2014 +0200 +++ b/test/src/jdk/nashorn/internal/codegen/CompilerTest.java Wed Oct 15 19:50:03 2014 +0530 @@ -72,6 +72,7 @@ options.set("print.parse", true); options.set("scripting", true); options.set("const.as.var", true); + options.set("verify.code", true); final ErrorManager errors = new ErrorManager() { @Override diff -r ef1e5e03e03e -r 2bf4c14345aa test/src/jdk/nashorn/internal/runtime/TrustedScriptEngineTest.java --- a/test/src/jdk/nashorn/internal/runtime/TrustedScriptEngineTest.java Wed Oct 15 16:00:21 2014 +0200 +++ b/test/src/jdk/nashorn/internal/runtime/TrustedScriptEngineTest.java Wed Oct 15 19:50:03 2014 +0530 @@ -325,4 +325,29 @@ ); assertEquals(ret, 10, "Parsed and executed OK"); } + + @Test + public void evalDefaultFileNameTest() throws ScriptException { + final NashornScriptEngineFactory fac = new NashornScriptEngineFactory(); + final ScriptEngine engine = fac.getScriptEngine(new String[] { "--verify-code=true" }); + // default FILENAME being "" make sure generated code bytecode verifies. + engine.eval("var a = 3;"); + } + + @Test + public void evalFileNameWithSpecialCharsTest() throws ScriptException { + final NashornScriptEngineFactory fac = new NashornScriptEngineFactory(); + final ScriptEngine engine = fac.getScriptEngine(new String[] { "--verify-code=true" }); + final ScriptContext ctxt = new SimpleScriptContext(); + // use file name with "dangerous" chars. + ctxt.setAttribute(ScriptEngine.FILENAME, "", ScriptContext.ENGINE_SCOPE); + engine.eval("var a = 3;"); + ctxt.setAttribute(ScriptEngine.FILENAME, "[myscript]", ScriptContext.ENGINE_SCOPE); + engine.eval("var h = 'hello';"); + ctxt.setAttribute(ScriptEngine.FILENAME, ";/\\$.", ScriptContext.ENGINE_SCOPE); + engine.eval("var foo = 'world';"); + // name used by jjs shell tool for the interactive mode + ctxt.setAttribute(ScriptEngine.FILENAME, "", ScriptContext.ENGINE_SCOPE); + engine.eval("var foo = 'world';"); + } }