Cause ed elementi da evitare di java.lang.VerifyError

1. Introduzione

In questo tutorial, esamineremo la causa degli errori java.lang.VerifyError e diversi modi per evitarlo.

2. Causa

La Java Virtual Machine (JVM) diffida di tutti i bytecode caricati come principio fondamentale del modello di sicurezza Java . Durante il runtime, la JVM caricherà i file .class e tenterà di collegarli insieme per formare un eseguibile, ma la validità di questi file .class caricati è sconosciuta.

Per garantire che i file .class caricati non rappresentino una minaccia per l'eseguibile finale, la JVM esegue la verifica sui file .class . Inoltre, la JVM garantisce che i file binari siano ben formati. Ad esempio, la JVM verificherà che le classi non sottotipizzino le classi finali .

In molti casi, la verifica non riesce su bytecode valido e non dannoso perché una versione più recente di Java ha un processo di verifica più rigoroso rispetto alle versioni precedenti . Ad esempio, JDK 13 potrebbe aver aggiunto un passaggio di verifica che non è stato applicato in JDK 7. Pertanto, se eseguiamo un'applicazione con JVM 13 e includiamo dipendenze compilate con una versione precedente di Java Compiler (javac), la JVM potrebbe considerare dipendenze obsolete non valide.

Pertanto, quando si collegano file .class meno recenti con una JVM più recente, la JVM potrebbe generare un'eccezione java.lang.VerifyError simile al seguente:

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

Esistono due modi per risolvere questo problema:

  • Aggiorna le dipendenze alle versioni compilate con un javac aggiornato
  • Disabilita la verifica Java

3. Soluzione di produzione

La causa più comune di un errore di verifica è il collegamento di file binari utilizzando una versione JVM più recente compilata con una versione precedente di javac . Ciò è più comune quando le dipendenze hanno bytecode generato da strumenti come Javassist , che potrebbe aver generato bytecode obsoleto se lo strumento è obsoleto.

Per risolvere questo problema, aggiorna le dipendenze a una versione creata utilizzando una versione JDK che corrisponda alla versione JDK utilizzata per creare l'applicazione . Ad esempio, se creiamo un'applicazione utilizzando JDK 13, le dipendenze dovrebbero essere create utilizzando JDK 13.

Per trovare una versione compatibile, ispezionare Build-Jdk nel file JAR Manifest della dipendenza per assicurarsi che corrisponda alla versione JDK utilizzata per creare l'applicazione.

4. Soluzione di debug e sviluppo

Durante il debug o lo sviluppo di un'applicazione, possiamo disabilitare la verifica come soluzione rapida.

Non utilizzare questa soluzione per il codice di produzione .

Disabilitando la verifica, la JVM può collegare codice dannoso o difettoso alle nostre applicazioni, con conseguenti compromissioni della sicurezza o arresti anomali durante l'esecuzione.

Si noti inoltre che a partire da JDK 13, questa soluzione è stata deprecata e non dovremmo aspettarci che questa soluzione funzioni nelle future versioni di Java. La disattivazione della verifica comporterà il seguente avviso:

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.

Il meccanismo per disabilitare la verifica del bytecode varia in base a come eseguiamo il nostro codice.

4.1. Riga di comando

Per disabilitare la verifica sulla riga di comando, passare il flag noverify al comando java :

java -noverify Foo.class

Nota che -noverify è una scorciatoia per -Xverify: nessuno ed entrambi possono essere usati in modo intercambiabile .

4.2. Esperto di

Per disabilitare la verifica in una build Maven, passa il flag noverify a qualsiasi plug-in desiderato:

 com.example.baeldung example-plugin   -noverify   

4.3. Gradle

Per disabilitare la verifica in una build Gradle, passa il flag noverify a qualsiasi attività desiderata:

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

5. conclusione

In questo breve tutorial, abbiamo appreso perché la JVM esegue la verifica del bytecode e cosa causa l' errore java.lang.VerifyError . Abbiamo anche esplorato due soluzioni: una di produzione e una di non produzione.

Quando possibile, utilizza le versioni più recenti delle dipendenze anziché disabilitare la verifica.