Fix JRuby embed crash after application reloading#4312
Merged
headius merged 1 commit intojruby:masterfrom Feb 24, 2017
Merged
Conversation
We use JRuby `ScriptingContainer` in a tomcat servlet web application. After application reloading in tomcat, JRuby runtime initialization fails with the error message. "BUG: could not initialize constructor handle" `MethodHandles.publicLookup().findConstructor()` fails with `IllegalAccessException` in static initialization block. The initialization does not work well with tomcat reloading. As a workaround `MethodHandles.lookup()` without access check works fine.
Contributor
Author
|
Here is a test code for the issue. With jruby-complete-9.1.6.0.jar, this fails with the following Exception. import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
public class TestReload {
public static void main(String[] args) {
try {
for (int i = 0; i < 2; i++) {
// load class
URLClassLoader loader = new URLClassLoader(new URL[] {
new URL("jar:file:./jruby-complete.jar!/")
});
Class<?> container = loader.loadClass("org.jruby.embed.ScriptingContainer");
Method runScriptlet = container.getMethod("runScriptlet", String.class);
Method setClassLoader = container.getMethod("setClassLoader", ClassLoader.class);
Object c = container.newInstance();
setClassLoader.invoke(c, loader);
runScriptlet.invoke(c, "puts \"Hello World!\"");
// unload class
loader = null;
c = null;
System.gc();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}$ java TestReload
Hello World!
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at TestReload.main(TestReload.java:18)
Caused by: java.lang.ExceptionInInitializerError
at org.jruby.runtime.ThreadContext.<init>(ThreadContext.java:201)
at org.jruby.runtime.ThreadContext.newContext(ThreadContext.java:76)
at org.jruby.internal.runtime.ThreadService.initMainThread(ThreadService.java:166)
at org.jruby.Ruby.init(Ruby.java:1238)
at org.jruby.Ruby.newInstance(Ruby.java:339)
at org.jruby.embed.internal.AbstractLocalContextProvider.getGlobalRuntime(AbstractLocalContextProvider.java:82)
at org.jruby.embed.internal.SingletonLocalContextProvider.getRuntime(SingletonLocalContextProvider.java:99)
at org.jruby.embed.internal.EmbedRubyRuntimeAdapterImpl.runParser(EmbedRubyRuntimeAdapterImpl.java:167)
at org.jruby.embed.internal.EmbedRubyRuntimeAdapterImpl.parse(EmbedRubyRuntimeAdapterImpl.java:94)
at org.jruby.embed.ScriptingContainer.parse(ScriptingContainer.java:1239)
at org.jruby.embed.ScriptingContainer.runScriptlet(ScriptingContainer.java:1299)
... 5 more
Caused by: java.lang.RuntimeException: BUG: could not initialize constructor handle
at org.jruby.runtime.scope.ManyVarsDynamicScope.<clinit>(ManyVarsDynamicScope.java:39)
... 16 more |
Contributor
Author
|
Threads would be needed to unload loaded classes. import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
public class TestReload {
public static void main(String[] args) {
while (true) {
Thread t = new Thread() {
public void run() {
try (URLClassLoader loader = new URLClassLoader(new URL[] {
new URL("jar:file:./jruby-complete.jar!/")
})) {
// load class
Class<?> container = loader.loadClass("org.jruby.embed.ScriptingContainer");
Method runScriptlet = container.getMethod("runScriptlet", String.class);
Method setClassLoader = container.getMethod("setClassLoader", ClassLoader.class);
Method terminate = container.getMethod("terminate");
Object c = container.newInstance();
setClassLoader.invoke(c, loader);
runScriptlet.invoke(c, "puts \"Hello World!\"");
terminate.invoke(c);
} catch (Exception e) {
e.printStackTrace();
}
// unload class
System.gc();
System.runFinalization();
System.gc();
}
};
t.start();
try {
t.join();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}$ java -XX:+TraceClassUnloading TestReload
(snip)
[thread 9492 also had an error]
#
# A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x000000006e4c24b0, pid=11608, tid=0x00000000000031e4
#
# JRE version: Java(TM) SE Runtime Environment (8.0_111-b14) (build 1.8.0_111-b14)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.111-b14 mixed mode windows-amd64 compressed oops)
# Problematic frame:
# C 0x000000006e4c24b0
#
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
#
# An error report file with more information is saved as:
(snip)hs_err_pid11608.log contains: |
Member
|
Nice investigation on this one. I'll try out your reproduction code and see if I can figure out what's going wrong. |
Member
|
Reproduced! Investigating. |
Member
|
Using MethodHandles.lookup() does indeed solve the issue, and I think it's a good change. The jnr-ffi crash is a separate issue and I'll investigate that. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
We use JRuby
ScriptingContainerin a tomcat servlet webapplication. After application reloading in tomcat, JRuby
runtime initialization fails with the error message.
"BUG: could not initialize constructor handle"
MethodHandles.publicLookup().findConstructor()fails withIllegalAccessExceptionin static initialization block.The initialization does not work well with tomcat reloading.
As a workaround
MethodHandles.lookup()without access checkworks fine.