Causes et évitement de l'erreur java.lang.VerifyError

1. Introduction

Dans ce didacticiel, nous examinerons la cause des erreurs java.lang.VerifyError et plusieurs moyens de les éviter.

2. Cause

La machine virtuelle Java (JVM) ne fait pas confiance à tout le bytecode chargé en tant que principe fondamental du modèle de sécurité Java . Pendant l'exécution, la machine virtuelle Java chargera les fichiers .class et tentera de les lier pour former un exécutable - mais la validité de ces fichiers .class chargés est inconnue.

Pour garantir que les fichiers .class chargés ne représentent pas une menace pour l'exécutable final, la machine virtuelle Java effectue une vérification sur les fichiers .class . De plus, la JVM garantit que les binaires sont bien formés. Par exemple, la JVM vérifiera que les classes ne sous-typent pas les classes finales .

Dans de nombreux cas, la vérification échoue sur un bytecode valide et non malveillant car une version plus récente de Java a un processus de vérification plus strict que les anciennes versions . Par exemple, JDK 13 peut avoir ajouté une étape de vérification qui n'a pas été appliquée dans JDK 7. Ainsi, si nous exécutons une application avec JVM 13 et incluons des dépendances compilées avec une version plus ancienne du compilateur Java (javac), la JVM peut considérer le dépendances obsolètes pour être invalides.

Ainsi, lors de la liaison de fichiers .class plus anciens avec une JVM plus récente, la JVM peut générer une erreur java.lang.VerifyError similaire à ce qui suit:

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

Il existe deux façons de résoudre ce problème:

  • Mettre à jour les dépendances vers des versions compilées avec un javac mis à jour
  • Désactiver la vérification Java

3. Solution de production

La cause la plus courante d'une erreur de vérification est la liaison de binaires à l'aide d'une version JVM plus récente compilée avec une ancienne version de javac . Ceci est plus courant lorsque les dépendances ont un bytecode généré par des outils tels que Javassist , qui peuvent avoir généré un bytecode obsolète si l'outil est obsolète.

Pour résoudre ce problème, mettez à jour les dépendances vers une version créée à l'aide d'une version JDK qui correspond à la version JDK utilisée pour générer l'application . Par exemple, si nous construisons une application à l'aide de JDK 13, les dépendances doivent être générées à l'aide de JDK 13.

Pour trouver une version compatible, inspectez le Build-Jdk dans le fichier JAR Manifest de la dépendance pour vous assurer qu'il correspond à la version JDK utilisée pour créer l'application.

4. Solution de débogage et de développement

Lors du débogage ou du développement d'une application, nous pouvons désactiver la vérification comme solution rapide.

N'utilisez pas cette solution pour le code de production .

En désactivant la vérification, la JVM peut lier un code malveillant ou défectueux à nos applications, entraînant des compromis de sécurité ou des plantages lors de son exécution.

Notez également qu'à partir du JDK 13, cette solution est obsolète et nous ne devons pas nous attendre à ce que cette solution fonctionne dans les futures versions de Java. La désactivation de la vérification entraînera l'avertissement suivant:

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.

Le mécanisme de désactivation de la vérification du bytecode varie en fonction de la façon dont nous exécutons notre code.

4.1. Ligne de commande

Pour désactiver la vérification sur la ligne de commande, passez l' indicateur noverify à la commande java :

java -noverify Foo.class

Notez que -noverify est un raccourci pour -Xverify: none et les deux peuvent être utilisés de manière interchangeable .

4.2. Maven

Pour désactiver la vérification dans une construction Maven, transmettez l' indicateur noverify à n'importe quel plugin souhaité:

 com.example.baeldung example-plugin   -noverify   

4.3. Gradle

Pour désactiver la vérification dans une version Gradle, transmettez l' indicateur noverify à n'importe quelle tâche souhaitée:

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

5. Conclusion

Dans ce rapide didacticiel, nous avons appris pourquoi la machine virtuelle Java effectue une vérification du bytecode et ce qui cause l' erreur java.lang.VerifyError . Nous avons également exploré deux solutions: une de production et une de non-production.

Lorsque cela est possible, utilisez les dernières versions des dépendances plutôt que de désactiver la vérification.