Рубрики
Без рубрики

Причины и избегание java.lang.VerifyError

Узнайте о причине java.lang.Ошибки VerifyError и несколько способов их избежать

Автор оригинала: Justin Albano.

1. введение

В этом уроке мы рассмотрим причину java.lang.VerifyError ошибки и множество способов их избежать.

2. Причина

Виртуальная машина Java (JVM) не доверяет всему загруженному байт-коду в качестве основного принципа модели безопасности Java . Во время выполнения JVM загрузит файлы .class и попытается связать их вместе, чтобы сформировать исполняемый файл, но достоверность этих загруженных файлов .class неизвестна.

Чтобы убедиться, что загруженные файлы .class не представляют угрозы для конечного исполняемого файла, JVM выполняет проверку для файлов .class . Кроме того, JVM гарантирует, что двоичные файлы хорошо сформированы. Например, JVM проверит, что классы не имеют подтипа final classes.

Во многих случаях проверка не выполняется на действительном, не вредоносном байт-коде, потому что более новая версия Java имеет более строгий процесс проверки, чем более старые версии . Например, JDK 13, возможно, добавил шаг проверки, который не был применен в JDK 7. Таким образом, если мы запустим приложение с JVM 13 и включим зависимости , скомпилированные с более старой версией компилятора Java (javac) , JVM может считать устаревшие зависимости недействительными.

Таким образом, при связывании старых файлов .class с более новой JVM JVM может выдать java.lang.VerifyError аналогично следующему:

java.lang.VerifyError: Expecting a stackmap frame at branch target X
Exception Details:
  Location:
    
com/example/baeldung.Foo(Lcom/example/baeldung/Bar:Baz;)Lcom/example/baeldung/Foo; @1: infonull
  Reason:
    Expected stackmap frame at this location.
  Bytecode:
    0000000: 0001 0002 0003 0004 0005 0006 0007 0008
    0000010: 0001 0002 0003 0004 0005 0006 0007 0008
    ...

Есть два способа решить эту проблему:

  • Обновите зависимости до версий, скомпилированных с обновленным javac
  • Отключить проверку Java

3. Производственное решение

Наиболее распространенной причиной ошибки проверки является связывание двоичных файлов с использованием более новой версии JVM, скомпилированной с более старой версией javac . Это более распространено , когда зависимости имеют байт-код, сгенерированный такими инструментами, как Javassist , которые, возможно, сгенерировали устаревший байт-код, если инструмент устарел.

Чтобы устранить эту проблему, обновите зависимости до версии |, построенной с использованием версии JDK, которая соответствует версии JDK, используемой для создания приложения . Например, если мы создаем приложение с использованием JDK 13, зависимости должны быть построены с использованием JDK 13.

Чтобы найти совместимую версию, проверьте Build-Jdk в файле манифеста JAR зависимости, чтобы убедиться, что она соответствует версии JDK, используемой для сборки приложения.

4. Решение для отладки и разработки

При отладке или разработке приложения мы можем отключить проверку в качестве быстрого исправления.

Не используйте это решение для производственного кода .

Отключив проверку, JVM может связать вредоносный или неисправный код с нашими приложениями, что приведет к нарушениям безопасности или сбоям при выполнении.

Также обратите внимание, что с JDK 13 это решение устарело , и мы не должны ожидать, что это решение будет работать в будущих выпусках Java. Отключение проверки приведет к следующему предупреждению:

Java HotSpot(TM) 64-Bit Server VM warning: Options -Xverify:none and -noverify were deprecated
  in JDK 13 and will likely be removed in a future release.

Механизм отключения проверки байт-кода зависит от того, как мы выполняем наш код.

4.1. Командная строка

Чтобы отключить проверку в командной строке, передайте флаг noverify команде java :

java -noverify Foo.class

Обратите внимание, что -noverify является ярлыком для -Xverify:none , и оба они могут использоваться взаимозаменяемо .

4.2. Maven

Чтобы отключить проверку в сборке Maven , передайте флаг noverify любому желаемому плагину:


    com.example.baeldung
    example-plugin
    
    
        -noverify
        
    

4.3. Gradle

Чтобы отключить проверку в сборке Gradle , передайте флаг noverify любой желаемой задаче:

someTask {
    // ...
    jvmArgs = jvmArgs << "-noverify"
}

5. Заключение

В этом кратком руководстве мы узнали, почему JVM выполняет проверку байт-кода и что вызывает java.lang.VerifyError ошибка. Мы также изучили два решения: производственное и непроизводственное.

Когда это возможно, используйте последние версии зависимостей вместо отключения проверки.