Wed, 18 Sep 2013 16:36:25 +0530
8024973: Using a different ScriptContext with a CompiledScript results in ScriptException
Reviewed-by: jlaskey, hannesw
1.1 --- a/src/jdk/nashorn/api/scripting/NashornScriptEngine.java Wed Sep 18 13:06:17 2013 +0530 1.2 +++ b/src/jdk/nashorn/api/scripting/NashornScriptEngine.java Wed Sep 18 16:36:25 2013 +0530 1.3 @@ -185,21 +185,12 @@ 1.4 1.5 @Override 1.6 public Object eval(final Reader reader, final ScriptContext ctxt) throws ScriptException { 1.7 - try { 1.8 - if (reader instanceof URLReader) { 1.9 - final URL url = ((URLReader)reader).getURL(); 1.10 - final Charset cs = ((URLReader)reader).getCharset(); 1.11 - return evalImpl(compileImpl(new Source(url.toString(), url, cs), ctxt), ctxt); 1.12 - } 1.13 - return evalImpl(Source.readFully(reader), ctxt); 1.14 - } catch (final IOException e) { 1.15 - throw new ScriptException(e); 1.16 - } 1.17 + return evalImpl(makeSource(reader, ctxt), ctxt); 1.18 } 1.19 1.20 @Override 1.21 public Object eval(final String script, final ScriptContext ctxt) throws ScriptException { 1.22 - return evalImpl(script.toCharArray(), ctxt); 1.23 + return evalImpl(makeSource(script, ctxt), ctxt); 1.24 } 1.25 1.26 @Override 1.27 @@ -221,16 +212,12 @@ 1.28 1.29 @Override 1.30 public CompiledScript compile(final Reader reader) throws ScriptException { 1.31 - try { 1.32 - return asCompiledScript(compileImpl(Source.readFully(reader), context)); 1.33 - } catch (final IOException e) { 1.34 - throw new ScriptException(e); 1.35 - } 1.36 + return asCompiledScript(makeSource(reader, context)); 1.37 } 1.38 1.39 @Override 1.40 public CompiledScript compile(final String str) throws ScriptException { 1.41 - return asCompiledScript(compileImpl(str.toCharArray(), context)); 1.42 + return asCompiledScript(makeSource(str, context)); 1.43 } 1.44 1.45 // Invocable methods 1.46 @@ -292,6 +279,29 @@ 1.47 1.48 // Implementation only below this point 1.49 1.50 + private static Source makeSource(final Reader reader, final ScriptContext ctxt) throws ScriptException { 1.51 + try { 1.52 + if (reader instanceof URLReader) { 1.53 + final URL url = ((URLReader)reader).getURL(); 1.54 + final Charset cs = ((URLReader)reader).getCharset(); 1.55 + return new Source(url.toString(), url, cs); 1.56 + } else { 1.57 + return new Source(getScriptName(ctxt), Source.readFully(reader)); 1.58 + } 1.59 + } catch (final IOException ioExp) { 1.60 + throw new ScriptException(ioExp); 1.61 + } 1.62 + } 1.63 + 1.64 + private static Source makeSource(final String src, final ScriptContext ctxt) { 1.65 + return new Source(getScriptName(ctxt), src); 1.66 + } 1.67 + 1.68 + private static String getScriptName(final ScriptContext ctxt) { 1.69 + final Object val = ctxt.getAttribute(ScriptEngine.FILENAME); 1.70 + return (val != null) ? val.toString() : "<eval>"; 1.71 + } 1.72 + 1.73 private <T> T getInterfaceInner(final Object thiz, final Class<T> clazz) { 1.74 if (clazz == null || !clazz.isInterface()) { 1.75 throw new IllegalArgumentException(getMessage("interface.class.expected")); 1.76 @@ -429,7 +439,7 @@ 1.77 // current ScriptContext exposed as "context" 1.78 // "context" is non-writable from script - but script engine still 1.79 // needs to set it and so save the context Property object 1.80 - contextProperty = newGlobal.addOwnProperty("context", NON_ENUMERABLE_CONSTANT, null); 1.81 + contextProperty = newGlobal.addOwnProperty("context", NON_ENUMERABLE_CONSTANT, ctxt); 1.82 // current ScriptEngine instance exposed as "engine". We added @SuppressWarnings("LeakingThisInConstructor") as 1.83 // NetBeans identifies this assignment as such a leak - this is a false positive as we're setting this property 1.84 // in the Global of a Context we just created - both the Context and the Global were just created and can not be 1.85 @@ -509,8 +519,8 @@ 1.86 throw new IllegalArgumentException(getMessage("interface.on.non.script.object")); 1.87 } 1.88 1.89 - private Object evalImpl(final char[] buf, final ScriptContext ctxt) throws ScriptException { 1.90 - return evalImpl(compileImpl(buf, ctxt), ctxt); 1.91 + private Object evalImpl(final Source src, final ScriptContext ctxt) throws ScriptException { 1.92 + return evalImpl(compileImpl(src, ctxt), ctxt); 1.93 } 1.94 1.95 private Object evalImpl(final ScriptFunction script, final ScriptContext ctxt) throws ScriptException { 1.96 @@ -561,11 +571,20 @@ 1.97 } 1.98 } 1.99 1.100 - private CompiledScript asCompiledScript(final ScriptFunction script) { 1.101 + private CompiledScript asCompiledScript(final Source source) throws ScriptException { 1.102 + final ScriptFunction func = compileImpl(source, context); 1.103 return new CompiledScript() { 1.104 @Override 1.105 public Object eval(final ScriptContext ctxt) throws ScriptException { 1.106 - return evalImpl(script, ctxt); 1.107 + final ScriptObject global = getNashornGlobalFrom(ctxt); 1.108 + // Are we running the script in the correct global? 1.109 + if (func.getScope() == global) { 1.110 + return evalImpl(func, ctxt, global); 1.111 + } else { 1.112 + // ScriptContext with a different global. Compile again! 1.113 + // Note that we may still hit per-global compilation cache. 1.114 + return evalImpl(compileImpl(source, ctxt), ctxt, global); 1.115 + } 1.116 } 1.117 @Override 1.118 public ScriptEngine getEngine() { 1.119 @@ -574,12 +593,6 @@ 1.120 }; 1.121 } 1.122 1.123 - private ScriptFunction compileImpl(final char[] buf, final ScriptContext ctxt) throws ScriptException { 1.124 - final Object val = ctxt.getAttribute(ScriptEngine.FILENAME); 1.125 - final String fileName = (val != null) ? val.toString() : "<eval>"; 1.126 - return compileImpl(new Source(fileName, buf), ctxt); 1.127 - } 1.128 - 1.129 private ScriptFunction compileImpl(final Source source, final ScriptContext ctxt) throws ScriptException { 1.130 return compileImpl(source, getNashornGlobalFrom(ctxt)); 1.131 }
2.1 --- a/src/jdk/nashorn/internal/runtime/Source.java Wed Sep 18 13:06:17 2013 +0530 2.2 +++ b/src/jdk/nashorn/internal/runtime/Source.java Wed Sep 18 16:36:25 2013 +0530 2.3 @@ -169,7 +169,7 @@ 2.4 2.5 final Source src = (Source)obj; 2.6 // Only compare content as a last resort measure 2.7 - return length == src.length && Objects.equals(name, src.name) && Arrays.equals(content, src.content); 2.8 + return length == src.length && Objects.equals(url, src.url) && Objects.equals(name, src.name) && Arrays.equals(content, src.content); 2.9 } 2.10 2.11 @Override
3.1 --- a/test/script/trusted/JDK-8008305.js Wed Sep 18 13:06:17 2013 +0530 3.2 +++ b/test/script/trusted/JDK-8008305.js Wed Sep 18 16:36:25 2013 +0530 3.3 @@ -54,6 +54,6 @@ 3.4 fail("Expected SecurityException from script!"); 3.5 } catch (e) { 3.6 if (! (e instanceof SecurityException)) { 3.7 - faile("Expected SecurityException, but got " + e); 3.8 + fail("Expected SecurityException, but got " + e); 3.9 } 3.10 }
4.1 --- a/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java Wed Sep 18 13:06:17 2013 +0530 4.2 +++ b/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java Wed Sep 18 16:36:25 2013 +0530 4.3 @@ -37,10 +37,12 @@ 4.4 import java.util.concurrent.Callable; 4.5 import javax.script.Compilable; 4.6 import javax.script.CompiledScript; 4.7 +import javax.script.ScriptContext; 4.8 import javax.script.ScriptEngine; 4.9 import javax.script.ScriptEngineFactory; 4.10 import javax.script.ScriptEngineManager; 4.11 import javax.script.ScriptException; 4.12 +import javax.script.SimpleScriptContext; 4.13 import org.testng.annotations.Test; 4.14 4.15 /** 4.16 @@ -231,6 +233,17 @@ 4.17 } 4.18 4.19 @Test 4.20 + public void compileAndEvalInDiffContextTest() throws ScriptException { 4.21 + final ScriptEngineManager m = new ScriptEngineManager(); 4.22 + final ScriptEngine engine = m.getEngineByName("js"); 4.23 + final Compilable compilable = (Compilable) engine; 4.24 + final CompiledScript compiledScript = compilable.compile("foo"); 4.25 + final ScriptContext ctxt = new SimpleScriptContext(); 4.26 + ctxt.setAttribute("foo", "hello", ScriptContext.ENGINE_SCOPE); 4.27 + assertEquals(compiledScript.eval(ctxt), "hello"); 4.28 + } 4.29 + 4.30 + @Test 4.31 public void accessGlobalTest() { 4.32 final ScriptEngineManager m = new ScriptEngineManager(); 4.33 final ScriptEngine e = m.getEngineByName("nashorn");