-
Bug
-
Resolution: Fixed
-
P4
-
8, 11, 17, 18, 19, 20
-
generic
-
generic
ADDITIONAL SYSTEM INFORMATION :
nashorn 15.4 / JDK 17
A DESCRIPTION OF THE PROBLEM :
Context.newBuiltinSwitchPoint raises an assertion when trying to access a lazily initialized built-in object like JSON from the Global scope.
It seems the code is not thread-safe and multiple parallel access during initialization can lead to an assertion error.
Previous versions of nashorn from JDK 1.8 without lazy global initialization did not have the problem.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the test code and after sometime you get an internal assertion
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Script execution is thread-safe
ACTUAL -
```
Caused by: java.lang.AssertionError
at org.openjdk.nashorn.internal.runtime.Context.newBuiltinSwitchPoint(Context.java:1737)
at org.openjdk.nashorn.internal.objects.Global.tagBuiltinProperties(Global.java:2950)
at org.openjdk.nashorn.internal.objects.Global.initConstructorAndSwitchPoint(Global.java:2552)
at org.openjdk.nashorn.internal.objects.Global.getBuiltinJSON(Global.java:2089)
at org.openjdk.nashorn.internal.objects.Global.getJSON(Global.java:294)
at org.openjdk.nashorn.internal.scripts.Script$Recompilation$79$17A$\^eval\_.entrypoint(<eval>:3)
at org.openjdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:648)
at org.openjdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:513)
at org.openjdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:520)
at org.openjdk.nashorn.api.scripting.ScriptObjectMirror.call(ScriptObjectMirror.java:111)
at org.example.AppTest.lambda$test$0(AppTest.java:46)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
```
---------- BEGIN SOURCE ----------
package org.example;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import javax.script.Bindings;
import javax.script.CompiledScript;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import org.junit.Test;
import org.openjdk.nashorn.api.scripting.JSObject;
import org.openjdk.nashorn.api.scripting.NashornScriptEngine;
public class AppTest {
@Test
public void test() throws InterruptedException, ExecutionException, ScriptException {
String script1 = """
var entrypoint = function(param) {
var out = busy(param);
return JSON.stringify({"out":out}); };
function busy(count) {
var j=0;
for (i=0;i<count;i++){j++;}
return j;
}""";
ExecutorService taskExecutor = Executors.newFixedThreadPool(100);
while (true) {
List<Future<Integer>> futures = new ArrayList<>();
ScriptEngineManager manager = new ScriptEngineManager();
NashornScriptEngine engine = (NashornScriptEngine) manager.getEngineByName("nashorn");
for (int i = 0; i < 10; i++) {
CompiledScript compiledScript = engine.compile(script1);
for (int j = 0; j < 1000; j++) {
futures.add(taskExecutor.submit(() -> {
Bindings bindings = compiledScript.getEngine().createBindings();
compiledScript.eval(bindings);
JSObject jsObject = (JSObject) bindings.get("entrypoint");
String jsonResult = (String) jsObject.call(null, 100);
return new ObjectMapper().readTree(jsonResult).get("out").intValue();
}));
}
}
for (Future<Integer> f : futures) {
f.get();
}
System.out.println(".");
TimeUnit.SECONDS.sleep(1);
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
load json in the context after compiling the script and before doing mulithreaded script calls
compiledScript.getEngine().eval("JSON")
FREQUENCY : always
nashorn 15.4 / JDK 17
A DESCRIPTION OF THE PROBLEM :
Context.newBuiltinSwitchPoint raises an assertion when trying to access a lazily initialized built-in object like JSON from the Global scope.
It seems the code is not thread-safe and multiple parallel access during initialization can lead to an assertion error.
Previous versions of nashorn from JDK 1.8 without lazy global initialization did not have the problem.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the test code and after sometime you get an internal assertion
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Script execution is thread-safe
ACTUAL -
```
Caused by: java.lang.AssertionError
at org.openjdk.nashorn.internal.runtime.Context.newBuiltinSwitchPoint(Context.java:1737)
at org.openjdk.nashorn.internal.objects.Global.tagBuiltinProperties(Global.java:2950)
at org.openjdk.nashorn.internal.objects.Global.initConstructorAndSwitchPoint(Global.java:2552)
at org.openjdk.nashorn.internal.objects.Global.getBuiltinJSON(Global.java:2089)
at org.openjdk.nashorn.internal.objects.Global.getJSON(Global.java:294)
at org.openjdk.nashorn.internal.scripts.Script$Recompilation$79$17A$\^eval\_.entrypoint(<eval>:3)
at org.openjdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:648)
at org.openjdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:513)
at org.openjdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:520)
at org.openjdk.nashorn.api.scripting.ScriptObjectMirror.call(ScriptObjectMirror.java:111)
at org.example.AppTest.lambda$test$0(AppTest.java:46)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
```
---------- BEGIN SOURCE ----------
package org.example;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import javax.script.Bindings;
import javax.script.CompiledScript;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import org.junit.Test;
import org.openjdk.nashorn.api.scripting.JSObject;
import org.openjdk.nashorn.api.scripting.NashornScriptEngine;
public class AppTest {
@Test
public void test() throws InterruptedException, ExecutionException, ScriptException {
String script1 = """
var entrypoint = function(param) {
var out = busy(param);
return JSON.stringify({"out":out}); };
function busy(count) {
var j=0;
for (i=0;i<count;i++){j++;}
return j;
}""";
ExecutorService taskExecutor = Executors.newFixedThreadPool(100);
while (true) {
List<Future<Integer>> futures = new ArrayList<>();
ScriptEngineManager manager = new ScriptEngineManager();
NashornScriptEngine engine = (NashornScriptEngine) manager.getEngineByName("nashorn");
for (int i = 0; i < 10; i++) {
CompiledScript compiledScript = engine.compile(script1);
for (int j = 0; j < 1000; j++) {
futures.add(taskExecutor.submit(() -> {
Bindings bindings = compiledScript.getEngine().createBindings();
compiledScript.eval(bindings);
JSObject jsObject = (JSObject) bindings.get("entrypoint");
String jsonResult = (String) jsObject.call(null, 100);
return new ObjectMapper().readTree(jsonResult).get("out").intValue();
}));
}
}
for (Future<Integer> f : futures) {
f.get();
}
System.out.println(".");
TimeUnit.SECONDS.sleep(1);
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
load json in the context after compiling the script and before doing mulithreaded script calls
compiledScript.getEngine().eval("JSON")
FREQUENCY : always