Scope leaked between contexts/optimization bug starting in Java 9
Ryan Berdeen
rberdeen at hubspot.com
Mon Aug 19 20:48:20 UTC 2019
I've encountered what seems like bug introduced in Java 9 where variables
can be leaked by the engine across separate contexts. I've extracted this
minimal reproduction out of service I'm running in projection in Java 8.
Gist: https://gist.github.com/also/412ce859f10f0b501bbfc43d15342dfc
Given this script
var x;
function test() {
x = 1;
print(++test.calls);
eval('');
}
test.calls = 0;
test();
Repeatedly running it with a new context in the same engine works fine in
Java 8 (it will print "1" forever), but in Java 9+, things get weird. I
tested on macOS in openjdk 12.0.2 2019-07-16 from Oracle.
ScriptEngine engine = new
ScriptEngineManager().getEngineByName("nashorn");
for (int i = 0; i < 20; i++) {
SimpleScriptContext context = new SimpleScriptContext();
Bindings bindings = engine.createBindings();
context.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
engine.eval(script, context);
}
This logs
1
2
3
4
...
If you add a second `engine.eval(script, context);` to the loop, it starts
to look like an optimization bug:
1
1
2
NaN
1
1
2
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
1
2
1
2
1
2
1
It seems to stabilize on 2, 1 after the 18th iteration. With a third call
to "engine.eval(script, context);" in the loop, it settles sooner:
1
1
1
2
NaN
NaN
1
1
1
1
1
1
It works as expected if you omit `context` in the calls to `engine.eval()`,
if you omit the `x = 1;` or `eval('');` lines in the `test` function, if
you call `print(++test.calls);` before `x = 1;`, or when using the
"graal.js" engine.
I know GraalVM JS is probably the way forward here, but was hoping I'd be
able to upgrade to Java 12 before making the switch.
More information about the nashorn-dev
mailing list