Ошибка Tomcat, когда код JNI использует env->FindClass() для загрузчиков классов

У меня возникают трудности при запуске веб-приложения, использующего OpenSplice DDS (6.1.0p5, распределение PrismTech) внутри Tomcat (8.0.21) с Oracle JRE (1.8u40).

Фон

Наш код использует библиотеки OpenSplice dcpscj.jar, dcpssaj.jar, dlrlsaj.jar. По причинам лицензирования и обслуживания они размещаются во внешнем каталоге /opt/OpenSpliceDDS/V6.1.0p6/HDE/x86.linux2.6/jar, а не встраиваются в файл WAR в обычном 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

Я также успешно сделал библиотеки доступными через свойство common.loader в conf/catalina.properties, согласно документации по загрузке классов tomcat.

проблема

Как с CLASSPATH, так и с подходом common.loader Tomcat постоянно аварийно завершает работу с SIG_SEGV при развертывании нашей WAR.

#
# 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
#

Верхняя часть стека

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

Анализ

Эта проблема возникает только тогда, когда JAR-файлы являются внешними по отношению к WEB-INF/lib, и если они "встроены" в WEB-INF/lib, Tomcat не падает.

org.example.dds.example_topic_typeTypeSupport (анонимный) - это код, сгенерированный OpenSplice, который мы упаковываем как отдельный JAR-файл в WEB-INF/lib.

example_topic_typeTypeSupport вызывает FooTypeSupportImpl.registerType(), который затем передает имя класса в виде строки в форме IDL "org::example::dds:example_topic_type" в часть JNI saj_fooTypeSupport.c.

За этим трудно следовать, но я считаю, что в конечном итоге env->FindClass вызывается с вариантом Java, то есть org.example.dds.example_topic_type. Похоже, это возвращает NULL, который затем передается в jni_GetMethodID, который вызывает segfault.

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

Согласно документации FindClass, используемый загрузчик классов - это тот, который содержит собственный метод.

FindClass находит загрузчик класса, связанный с текущим нативным методом; то есть загрузчик класса, который объявил нативный метод. Если нативный метод принадлежит системному классу, загрузчик классов не будет задействован

Это означает, что загрузчик классов используется для загрузки FooTypeSupportImpl, который находится в dcpssaj.jar. Этот загрузчик классов не может видеть наши определения тем, которые находятся в WEB-INF/lib/themes.jar.

Документация по загрузке классов Tomcat описывает частные загрузчики классов для каждого модуля.

  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

Вопрос

  • Есть ли способ включить дополнительные файлы JAR в Tomcat и загрузить их тем же загрузчиком классов, который использовался для загрузки других файлов JAR в WEB-INF/lib? Я ищу решение на основе чистой конфигурации - я уже рассматривал обходные пути, включая символические ссылки или трансплантацию файлов JAR DDS в файл WAR с помощью некоторого сценария во время развертывания.
  • Есть ли способ настроить OpenSplice DDS, чтобы избежать этой проблемы?

0 ответов

Другие вопросы по тегам