JNI не может найти класс в подписанном JAR, так как JRE 8u232 - PullRequest
6 голосов
/ 17 января 2020

У меня есть приложение Java с подписанным JAR, которое содержит все файлы классов и ресурсы. Приложение поставляется с JRE и исполняемым файлом. Этот исполняемый файл написан на C ++ и использует JNI для загрузки виртуальной машины и запуска приложения. В прошлом это работало безупречно.

Начиная с JRE 8u232 (например, Azul, но также 8u231 из Oracle), приложение больше не запускается, поскольку указанный основной класс не может быть найден с помощью функции FindClass() JNI. Он возвращает нулевой указатель, и когда я затем вызываю функцию ExceptionDescribe(), он показывает NPE, возникающий в методе Java JarVerifier::processEntry:

Exception in thread "main" java.lang.NullPointerException
    at java.util.jar.JarVerifier.processEntry(JarVerifier.java:303)
    at java.util.jar.JarVerifier.update(JarVerifier.java:230)
    at java.util.jar.JarFile.initializeVerifier(JarFile.java:383)
    at java.util.jar.JarFile.ensureInitialization(JarFile.java:612)
    at java.util.jar.JavaUtilJarAccessImpl.ensureInitialization(JavaUtilJarAccessImpl.java:69)
    at sun.misc.URLClassPath$JarLoader$2.getManifest(URLClassPath.java:991)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:451)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:351)

Когда я удаляю * .RSA и * .SF файлы из папки JAR META-INF снова работают. Это также работает, когда я вызываю «java» исполняемый файл из папки «bin» JRE, например:

java -cp "path/to/my/jar" org.company.name.MyMainclass

Мне кажется, что что-то изменилось относительно Java 8 (или новее) ) что вызывает эту проблему. Однако я не могу найти причину. В чем здесь может быть проблема?

Обновление:

Я сделал некоторую удаленную отладку с классом JarVerifier и заметил следующее:

  • JarVerifier::process обращается к хэш-карте sigFileData несколько раз (строка № 303) с помощью get()
  • в некоторой точке, вызывается JarVerifier::doneWithMeta, что устанавливает карту в null, прежде чем ее метод get() будет вызван снова
  • это происходит только при запуске приложения через JNI

Обновление 2:

Я выяснил причину проблемы и получил мое приложение снова работать, но я не понимаю почему. Исполняемый файл, который запускает приложение, читает текстовый файл с несколькими параметрами для передачи на виртуальную машину (например, системные свойства, имя основного класса и т. Д. c). Один параметр устанавливает системное свойство java.util.logging.config.file в файл logging.properties в том же каталоге. Этот файл свойств начинается следующим образом:

handlers = org.mycompany.juli2log4j.JuliToLog4jHandler
.handlers = org.mycompany.juli2log4j.JuliToLog4jHandler

Эти операторы и класс обработчика были записаны 10 лет go. Когда я удаляю оператор «.handlers», мое приложение работает, и ведение журнала все еще работает нормально.

Больше всего меня удивляет то, как эта строка вызовет исключение NullPointerException в классе JarVerifier при запуске приложения. Как это может быть? Какая связь?

1 Ответ

3 голосов
/ 20 января 2020

Документация LogManager предполагает, что .handlers недопустимо, поскольку в нем отсутствует спецификатор регистратора:

Свойство " .handlers". Это определяет пробел или разделенный запятыми список имен классов для классов обработчиков, которые нужно загружать и регистрировать в качестве обработчиков для указанного регистратора. Каждое имя класса должно быть для класса Handler, который имеет конструктор по умолчанию. Обратите внимание, что эти обработчики могут создаваться лениво, когда они впервые используются.

Я предполагаю, что 8u232 внесло изменение, которое больше не обрабатывает (или выводит) отсутствующее имя регистратора. Либо, скорее всего, сопоставление с null, которое раньше не существовало, и / или новая ссылка на регистратор с ключом null.

...