Ursachen und Vermeidung von java.lang.VerifyError

1. Einleitung

In diesem Tutorial untersuchen wir die Ursache von java.lang.VerifyError- Fehlern und verschiedene Möglichkeiten, dies zu vermeiden.

2. Ursache

Die Java Virtual Machine (JVM) misstraut allen geladenen Bytecodes als Grundprinzip des Java-Sicherheitsmodells . Zur Laufzeit lädt die JVM .class- Dateien und versucht, sie zu einer ausführbaren Datei zu verknüpfen. Die Gültigkeit dieser geladenen .class- Dateien ist jedoch unbekannt.

Um sicherzustellen, dass die geladenen .class- Dateien keine Bedrohung für die endgültige ausführbare Datei darstellen, führt die JVM eine Überprüfung der .class- Dateien durch. Darüber hinaus stellt die JVM sicher, dass die Binärdateien gut geformt sind. Beispielsweise überprüft die JVM, ob Klassen keine endgültigen Klassen subtypisieren .

In vielen Fällen schlägt die Überprüfung bei gültigem, nicht böswilligem Bytecode fehl, da eine neuere Version von Java einen strengeren Überprüfungsprozess aufweist als ältere Versionen . Beispielsweise hat JDK 13 möglicherweise einen Überprüfungsschritt hinzugefügt, der in JDK 7 nicht erzwungen wurde. Wenn wir also eine Anwendung mit JVM 13 ausführen und Abhängigkeiten einschließen, die mit einer älteren Version des Java-Compilers (javac) kompiliert wurden, kann die JVM dies berücksichtigen veraltete Abhängigkeiten sind ungültig.

Wenn ältere .class- Dateien mit einer neueren JVM verknüpft werden , kann die JVM daher einen java.lang.VerifyError auslösen , der dem folgenden ähnelt:

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

Es gibt zwei Möglichkeiten, um dieses Problem zu lösen:

  • Aktualisieren Sie die Abhängigkeiten auf Versionen, die mit einem aktualisierten Javac kompiliert wurden
  • Deaktivieren Sie die Java-Überprüfung

3. Produktionslösung

Die häufigste Ursache für einen Überprüfungsfehler ist das Verknüpfen von Binärdateien mit einer neueren JVM-Version, die mit einer älteren Version von javac kompiliert wurde . Dies ist häufiger der Fall , wenn für Abhängigkeiten Bytecode von Tools wie Javassist generiert wurde , der möglicherweise veralteten Bytecode generiert hat, wenn das Tool veraltet ist.

Um dieses Problem zu beheben, aktualisieren Sie die Abhängigkeiten auf eine Version, die mit einer JDK-Version erstellt wurde, die mit der JDK-Version übereinstimmt, die zum Erstellen der Anwendung verwendet wurde . Wenn wir beispielsweise eine Anwendung mit JDK 13 erstellen, sollten die Abhängigkeiten mit JDK 13 erstellt werden.

Um eine kompatible Version zu finden, überprüfen Sie das Build-Jdk in der JAR-Manifest-Datei der Abhängigkeit, um sicherzustellen, dass es mit der JDK-Version übereinstimmt, die zum Erstellen der Anwendung verwendet wurde.

4. Debugging- und Entwicklungslösung

Beim Debuggen oder Entwickeln einer Anwendung können wir die Überprüfung als schnelle Lösung deaktivieren.

Verwenden Sie diese Lösung nicht für Produktionscode .

Durch Deaktivieren der Überprüfung kann die JVM schädlichen oder fehlerhaften Code mit unseren Anwendungen verknüpfen, was zu Sicherheitslücken oder Abstürzen bei der Ausführung führt.

Beachten Sie auch, dass diese Lösung ab JDK 13 veraltet ist und wir nicht erwarten sollten, dass diese Lösung in zukünftigen Java-Versionen funktioniert. Das Deaktivieren der Überprüfung führt zu der folgenden Warnung:

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.

Der Mechanismus zum Deaktivieren der Bytecode-Überprüfung hängt davon ab, wie wir unseren Code ausführen.

4.1. Befehlszeile

Übergeben Sie das Noverify- Flag an den Java- Befehl , um die Überprüfung in der Befehlszeile zu deaktivieren :

java -noverify Foo.class

Beachten Sie, dass -noverify eine Verknüpfung für -Xverify ist: none und beide können austauschbar verwendet werden .

4.2. Maven

Um die Überprüfung in einem Maven-Build zu deaktivieren, übergeben Sie das Noverify- Flag an ein beliebiges Plugin:

 com.example.baeldung example-plugin   -noverify   

4.3. Gradle

Übergeben Sie das Noverify- Flag an eine beliebige Aufgabe , um die Überprüfung in einem Gradle-Build zu deaktivieren :

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

5. Schlussfolgerung

In diesem kurzen Tutorial haben wir erfahren, warum die JVM die Bytecode-Überprüfung durchführt und was den Fehler java.lang.VerifyError verursacht. Wir haben auch zwei Lösungen untersucht: eine Produktionslösung und eine Nichtproduktionslösung.

Verwenden Sie nach Möglichkeit die neuesten Versionen von Abhängigkeiten, anstatt die Überprüfung zu deaktivieren.