Java >> Java tutorial >  >> Tag >> java.lang

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

1. Introduktion

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

2. Årsag

Java Virtual Machine (JVM) har mistillid til al indlæst bytekode som en kerne i Java Security Model . Under kørsel vil JVM'en indlæse .class filer og forsøg at linke dem sammen for at danne en eksekverbar - men gyldigheden af ​​disse indlæste .class filer er ukendt.

For at sikre, at den indlæste .class filer ikke udgør en trussel mod den endelige eksekverbare, udfører JVM'en verifikation på .class filer. Derudover sikrer JVM, at binære filer er velformede. For eksempel vil JVM bekræfte, at klasser ikke undertyper final klasser.

I mange tilfælde mislykkes verifikationen på gyldig, ikke-ondsindet bytekode, fordi en nyere version af Java har en strengere bekræftelsesproces 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 overveje forældede afhængigheder er ugyldige.

Således, når du linker ældre .class filer med en nyere JVM, kan JVM'en kaste en java.lang.VerifyError ligner følgende:

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

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

  • Opdater afhængigheder til versioner, der er kompileret med en opdateret javac
  • Deaktiver Java-bekræftelse

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 bytekode genereret af værktøjer såsom Javassist , som kan have genereret forældet bytekode, hvis værktøjet er forældet.

For at løse dette problem skal du opdatere afhængigheder til en version bygget ved hjælp af en JDK-version, der matcher den JDK-version, der blev brugt til at bygge 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 Manifest-filen for afhængigheden for at sikre, at den matcher den JDK-version, der blev brugt til at bygge applikationen.

4. Fejlfindings- og udviklingsløsning

Når vi fejlretter 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 sikkerhedskompromitteringer eller nedbrud, når det udføres.

Bemærk også, at fra og med JDK 13 er denne løsning blevet forældet, og vi skal ikke forvente, at denne løsning virker i fremtidige Java-udgivelser. Deaktivering af bekræftelse vil resultere i følgende advarsel:

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.

Mekanismen til at deaktivere bytekodebekræftelse varierer baseret på, hvordan vi kører vores kode.

4.1. Kommandolinje

For at deaktivere verifikation på kommandolinjen skal du videregive noverify flag til java kommando:

java -noverify Foo.class

Bemærk, at -noverify er en genvej til-Xverify:none og begge kan bruges i flæng.

4.2. Maven

For at deaktivere bekræftelse i en Maven-build skal du bestå noverificeringen flag til ethvert ønsket plugin:

<plugin>
    <groupId>com.example.baeldung</groupId>
    <artifactId>example-plugin</artifactId>
    <!-- ... -->
    <configuration>
        <argLine>-noverify</argLine>
        <!-- ... -->
    </configuration>
</plugin>

4.3. Gradle

For at deaktivere bekræftelse i en Gradle-build skal du bestå noverify flag til enhver ønsket opgave:

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

5. Konklusion

I denne hurtige vejledning lærte vi, hvorfor JVM'en udfører bytekodebekræftelse, og hvad der forårsager java.lang.VerifyError fejl. Vi udforskede også to løsninger:En produktionsløsning og en ikke-produktionsløsning.

Når det er muligt, brug de nyeste versioner af afhængigheder  i stedet for at deaktivere verifikation.


Java tag