Årsager og undgåelse af java.lang.VerifyError

1. Introduktion

I denne vejledning ser vi på årsagen til java.lang.VerifyError fejl og flere måder at undgå det på.

2. Årsag

Det Java Virtual Machine (JVM) mistroer alt indlæst bytecode som en grundlæggende princip i Java Security Model. Under runtime indlæses JVM .klasse filer og forsøge at kæde dem sammen for at danne en eksekverbar - men gyldigheden af ​​disse indlæses .klasse filer er ukendt.

For at sikre, at den indlæste .klasse filer udgør ikke en trussel mod den endelige eksekverbare, JVM udfører verifikation på .klasse filer. Derudover sikrer JVM, at binærfiler er velformede. For eksempel vil JVM kontrollere, at klasser ikke undertype endelig klasser.

I mange tilfælde mislykkes verifikation af gyldig, ikke-ondsindet bytecode, fordi en nyere version af Java har en strengere verifikationsproces end ældre versioner. For eksempel kan JDK 13 have tilføjet et verifikationstrin, der ikke blev håndhævet i JDK 7. Hvis vi kører en applikation med JVM 13 og inkluderer afhængigheder kompileret med en ældre version af Java Compiler (javac), kan JVM muligvis overveje forældede afhængigheder for at være ugyldige.

Således når man forbinder ældre .klasse filer med en nyere JVM, JVM kan kaste et java.lang.VerifyError svarende til følgende:

java.lang.VerifyError: Forventer en stackmap-ramme ved grenmål X Undtagelsesdetaljer: Placering: com / eksempel / baeldung.Foo (Lcom / eksempel / baeldung / Bar: Baz;) Lcom / eksempel / baeldung / Foo; @ 1: infonull Årsag: Forventet stackmap-ramme på dette sted. Bykode: 0000000: 0001 0002 0003 0004 0005 0006 0007 0008 0000010: 0001 0002 0003 0004 0005 0006 0007 0008 ...

Der er to måder at løse dette problem på:

  • Opdater afhængigheder til versioner kompileret med en opdateret javac
  • Deaktiver Java-verifikation

3. Produktionsløsning

Den mest almindelige årsag til en verifikationsfejl er at linke binære filer ved hjælp af en nyere JVM-version kompileret med en ældre version af javac. Dette er mere almindeligt når afhængigheder har bytecode genereret af værktøjer som Javassist, som muligvis har genereret forældet bytecode, hvis værktøjet er forældet.

For at løse dette problem, opdater afhængigheder til enversion bygget ved hjælp af en JDK-version, der matcher den JDK-version, der blev brugt til at oprette applikationen. For eksempel, hvis vi bygger en applikation ved hjælp af JDK 13, skal afhængighederne bygges ved hjælp af JDK 13.

For at finde en kompatibel version skal du inspicere Build-Jdk i JAR-manifestfilen af ​​afhængighed for at sikre, at den matcher den JDK-version, der blev brugt til at oprette applikationen.

4. Fejlfinding og udviklingsløsning

Når vi fejler eller udvikler en applikation, kan vi deaktivere bekræftelse som en hurtig løsning.

Brug ikke denne løsning til produktionskode.

Ved at deaktivere verifikation kan JVM linke ondsindet eller defekt kode til vores applikationer, hvilket resulterer i sikkerhedskompromisser eller nedbrud, når de udføres.

Bemærk også, at fra og med JDK 13 er denne løsning udfaset, og vi bør ikke forvente, at denne løsning fungerer i fremtidige Java-udgivelser. Deaktivering af verifikation vil resultere i følgende advarsel:

Java HotSpot (TM) 64-bit server-VM-advarsel: Indstillinger -Xverify: none og -noverify blev udfaset i JDK 13 og vil sandsynligvis blive fjernet i en fremtidig udgivelse.

Mekanismen til deaktivering af bytecode-verifikation varierer afhængigt af, hvordan vi kører vores kode.

4.1. Kommandolinje

For at deaktivere bekræftelse på kommandolinjen skal du passere ikke bekræfte flag til java kommando:

java -overvåge Foo.class

Noter det -underret er en genvej til-Kontrol: ingen og begge kan bruges om hverandre.

4.2. Maven

For at deaktivere verifikation i en Maven-build skal du videregive ikke bekræfte flag til ethvert ønsket plugin:

 com.example.baeldung eksempel-plugin -overvåge 

4.3. Gradle

For at deaktivere verifikation i en Gradle-build skal du videregive Bekræft flag til en ønsket opgave:

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

5. Konklusion

I denne hurtige vejledning lærte vi, hvorfor JVM udfører bytecode-verifikation, og hvad der forårsager java.lang.VerifyError fejl. Vi undersøgte også to løsninger: En produktion og en ikke-produktion.

Når det er muligt, Brug de nyeste versioner af afhængigheder snarere end at deaktivere verifikation.