JDK-8060688 : Nashorn: Generated script class name fails --verify-code for names with special chars
  • Type: Bug
  • Component: core-libs
  • Sub-Component: jdk.nashorn
  • Affected Version: 8u20,9
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_7
  • CPU: x86_64
  • Submitted: 2014-10-13
  • Updated: 2015-06-04
  • Resolved: 2014-10-15
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8 JDK 9
8u40Fixed 9 b36Fixed
Description
FULL PRODUCT VERSION :
java version "1.8.0_20"
Java(TM) SE Runtime Environment (build 1.8.0_20-b26)
Java HotSpot(TM) 64-Bit Server VM (build 25.20-b23, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.1.7601]

A DESCRIPTION OF THE PROBLEM :
When using the --verify-code option with Nashorn, the behaviour is not consistent depending on how a script is evaluated. Using jjs with a script file containing the script works fine, but using jjs to interactively execute a script or using a custom instantiated NashornScriptEngine or eval() from within a Java application always fails with an error during byte code verification when --verify-code=true option is set.
When eval() is used with a ScriptContext that contains a ScriptEngine.FILENAME attribute, --verify-code=true will cause a failure when the file name is invalid based on some rule set.



STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1) Execute any (trivial) script contained in a file via jjs e.g.
jjs --verify-code=true myScript.js

2) Start jjs to execute script in interactive shell mode
jjs --verify-code=true

3) Run provided Java test class "Main"

4) Run provided Java test class "Main2"

5) Run provided Java test class "Main3"

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Script and application terminate without any issue.
ACTUAL -
Only jjs in step 1) and eval() in step 4) succeed, steps 2), 3) and 5) fail with IllegalArgumentException during byte code verification.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread "main" java.lang.IllegalArgumentException: Invalid class name (must be a fully qualified class name in internal form): jdk/nashorn/internal/scripts/Script$\^eval\_
	at jdk.internal.org.objectweb.asm.util.CheckMethodAdapter.checkInternalName(CheckMethodAdapter.java:1380)
	at jdk.internal.org.objectweb.asm.util.CheckMethodAdapter.checkInternalName(CheckMethodAdapter.java:1347)
	at jdk.internal.org.objectweb.asm.util.CheckClassAdapter.visit(CheckClassAdapter.java:412)
	at jdk.internal.org.objectweb.asm.ClassReader.accept(ClassReader.java:651)
	at jdk.internal.org.objectweb.asm.ClassReader.accept(ClassReader.java:535)
	at jdk.internal.org.objectweb.asm.util.CheckClassAdapter.verify(CheckClassAdapter.java:241)
	at jdk.nashorn.internal.runtime.Context.verify(Context.java:889)
	at jdk.nashorn.internal.runtime.Context$ContextCodeInstaller.verify(Context.java:174)
	at jdk.nashorn.internal.codegen.CompilationPhase$8.transform(CompilationPhase.java:414)
	at jdk.nashorn.internal.codegen.CompilationPhase.apply(CompilationPhase.java:513)
	at jdk.nashorn.internal.codegen.Compiler.compile(Compiler.java:361)
	at jdk.nashorn.internal.runtime.Context.compile(Context.java:1071)
	at jdk.nashorn.internal.runtime.Context.compileScript(Context.java:1019)
	at jdk.nashorn.internal.runtime.Context.compileScript(Context.java:490)
	at jdk.nashorn.api.scripting.NashornScriptEngine.compileImpl(NashornScriptEngine.java:651)
	at jdk.nashorn.api.scripting.NashornScriptEngine.compileImpl(NashornScriptEngine.java:640)
	at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:521)
	at jdk.nashorn.api.scripting.NashornScriptEngine.eval(NashornScriptEngine.java:192)
	at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:264)

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import javax.script.ScriptEngine;
import jdk.nashorn.api.scripting.NashornScriptEngineFactory;

public class Main
{
   public static void main(final String[] args) throws Exception
   {
      NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
      ScriptEngine scriptEngine = factory.getScriptEngine(new String[]{"--verify-code=true"});
      scriptEngine.eval("var a = 3;");
   }
}

import javax.script.ScriptEngine;
import javax.script.ScriptContext;
import javax.script.SimpleScriptContext;
import jdk.nashorn.api.scripting.NashornScriptEngineFactory;

public class Main2
{
   public static void main(final String[] args) throws Exception
   {
      NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
      ScriptEngine scriptEngine = factory.getScriptEngine(new String[]{"--verify-code=true"});
      ScriptContext ctxt = new SimpleScriptContext();
      ctxt.setAttribute(ScriptEngine.FILENAME, "works", ScriptContext.ENGINE_SCOPE);
      scriptEngine.eval("var a = 3;");
   }
}


import javax.script.ScriptEngine;
import javax.script.ScriptContext;
import javax.script.SimpleScriptContext;
import jdk.nashorn.api.scripting.NashornScriptEngineFactory;

public class Main3
{
   public static void main(final String[] args) throws Exception
   {
      NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
      ScriptEngine scriptEngine = factory.getScriptEngine(new String[]{"--verify-code=true"});
      ScriptContext ctxt = new SimpleScriptContext();
      ctxt.setAttribute(ScriptEngine.FILENAME, "<fails>", ScriptContext.ENGINE_SCOPE);
      scriptEngine.eval("var a = 3;");
   }
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Execute script without --verify-code option always solves the issue.

When executing a script via eval(String) from a Java application, using eval(String, ScriptContext) always solves the issue when the attribute ScriptEngine.FILENAME is set to a valid file name (whatever is accepted as "valid").


Comments
While this is a ASM bug, we need an interim workaround fix in nashorn - so that nashorn will run fine with --verify-code for the offending cases.
15-10-2014

While this is a ASM bug, we need an interim workaround fix in nashorn - so that nashorn will run fine with --verify-code for the offending cases.
15-10-2014

This is a ASM bug exposed by Nashorn. Please evaluate.
14-10-2014

Nashorn generates internal class names with characters accepted by JVM. For example, "<shell>", "<eval>" etc. are used as part of generated class name. And such characters are escaped as required by JVM spec. For example, you can do jjs -Xverify:all jjs> print("hello"); whereas Nashorn's --verify-code option uses ASM bytecode verifier - which uses CheckMethodAdapter.checkIdentifier which forces characters to be "java-identifier-part" - so jjs --verify-code ends up throwing error. It should not - it does because of the bug (overly strict check) in ASM.
14-10-2014