Tomcat segfault when JNI code uses env->FindClass() across classloaders

632 Views Asked by At

I'm having difficulties running a web application that uses OpenSplice DDS (6.1.0p5, PrismTech distriburation) inside Tomcat (8.0.21) with Oracle JRE (1.8u40).

Background

Our code uses the OpenSplice libraries dcpscj.jar, dcpssaj.jar, dlrlsaj.jar. For licensing and maintenance reasons these are hosted in an external directory /opt/OpenSpliceDDS/V6.1.0p6/HDE/x86.linux2.6/jar rather than being embedded in the WAR file in the usual WEB-INF/lib.

setenv.sh

export CLASSPATH=/opt/OpenSpliceDDS/V6.1.0p6/HDE/x86.linux2.6/jar/dcpscj.jar:/opt/OpenSpliceDDS/V6.1.0p6/HDE/x86.linux2.6/jar/dcpssaj.jar:/opt/OpenSpliceDDS/V6.1.0p6/HDE/x86.linux2.6/jar/dlrlsaj.jar
export CATALINA_OPTS=-Djava.library.path=/opt/OpenSpliceDDS/V6.1.0p6/HDE/x86.linux2.6/lib
export LD_PRELOAD=/usr/java/jre/lib/i386/libjsig.so

I've also successfully made the libraries available via the common.loader property in conf/catalina.properties, as per tomcat classloading documentation.

Problem

With both CLASSPATH and common.loader approaches Tomcat consistently crashes with a SIG_SEGV when our WAR is deployed.

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x0142043a, pid=17613, tid=2004876144
#
# JRE version: Java(TM) SE Runtime Environment (8.0_40-b25) (build 1.8.0_40-b25)
# Java VM: Java HotSpot(TM) Server VM (25.40-b25 mixed mode linux-x86 )
# Problematic frame:
# V  [libjvm.so+0x53543a]  get_method_id(JNIEnv_*, _jclass*, char const*, char const*, bool, Thread*)+0x7a
#
# Core dump written. Default location: //core or core.17613
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
#

The top part of the stack

V  [libjvm.so+0x53543a]  get_method_id(JNIEnv_*, _jclass*, char const*, char const*, bool, Thread*)+0x7a
V  [libjvm.so+0x5467ad]  jni_GetMethodID+0xbd
C  [libdcpssaj.so+0x1569e]  saj_cacheStructBuild+0x10e
C  [libdcpssaj.so+0x148ae]  saj_metaObject+0x9e
C  [libdcpssaj.so+0x14b76]  saj_copyCacheBuild+0x56
C  [libdcpssaj.so+0x14c34]  saj_copyCacheNew+0x94
C  [libdcpssaj.so+0x29dcf]  Java_org_opensplice_dds_dcps_FooTypeSupportImpl_jniRegisterType+0x21f
j  org.opensplice.dds.dcps.FooTypeSupportImpl.jniRegisterType(Ljava/lang/Object;LDDS/DomainParticipant;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I+0
j  org.opensplice.dds.dcps.FooTypeSupportImpl.registerType(Ljava/lang/Object;LDDS/DomainParticipant;Ljava/lang/String;)I+17
j  org.example.dds.example_topic_typeTypeSupport.register_type(LDDS/DomainParticipant;Ljava/lang/String;)I+3

Analysis

This problem only occurs when JARs are external to WEB-INF/lib, if they are 'embedded' in WEB-INF/lib, Tomcat does not crash.

org.example.dds.example_topic_typeTypeSupport (anonymised) is code generated by OpenSplice that we package as a separate JAR in WEB-INF/lib.

example_topic_typeTypeSupport calls FooTypeSupportImpl.registerType() which then passes the classname as a String in IDL form "org::example::dds:example_topic_type" into the JNI part saj_fooTypeSupport.c.

It's hard to follow, but I believe eventually env->FindClass is called with the Java variant i.e. org.example.dds.example_topic_type. This appears to be returning NULL which is then passed into jni_GetMethodID which causes the segfault.

javaClass = (*(ctx->javaEnv))->FindClass (ctx->javaEnv, classDescriptor);

According to the FindClass documentation the classloader that is used is the one that hosts the native method.

FindClass locates the class loader associated with the current native method; that is, the class loader of the class that declared the native method. If the native method belongs to a system class, no class loader will be involved

This means that the classloader is the one used to load FooTypeSupportImpl which lives in dcpssaj.jar. This class loader cannot see our topic definitions which live in WEB-INF/lib/topics.jar.

The Tomcat classloading documentation describes private classloaders for each module

  Bootstrap
      |
   System   <=== if dcpssaj.jar is loaded here then it can't see example_topic_type in topics.jar
      |
   Common   <=== if dcpssaj.jar is loaded here then it can't see example_topic_type in topics.jar
    /       
 Webapp1  <=== WEB-INF/lib/topics.jar containing example_topic_type

Question

  • Is there anyway to include extra JAR files in Tomcat and have them loaded by the same classloader used to load other JARs in WEB-INF/lib? I'm looking for clean configuration based solution - I've already considered workarounds including symlinks or transplanting the DDS JARs into the WAR file via some script at time of deployment.
  • Is there anyway to configure OpenSplice DDS to avoid this issue?
0

There are 0 best solutions below