Causas e Prevenção de java.lang.VerifyError
1. Introdução
Neste tutorial, veremos a causa dos errosjava.lang.VerifyError e várias maneiras de evitá-los.
2. Causa
OJava Virtual Machine (JVM) distrusts all loaded bytecode as a core tenet of the Java Security Model. Durante o tempo de execução, a JVM carregará os arquivos.class e tentará vinculá-los para formar um executável - mas a validade desses arquivos.class carregados é desconhecida.
Para garantir que os arquivos.class carregados não representem uma ameaça ao executável final, a JVM executaverification on the .class files. Além disso, a JVM garante que os binários sejam bem formados. Por exemplo, a JVM verificará se as classes não têm subtipofinal classes.
Em muitos casos, a verificação falha em bytecode válido e não malicioso porquea newer version of Java has a stricter verification process than older versions. Por exemplo, o JDK 13 pode ter adicionado uma etapa de verificação que não foi imposta no JDK 7. Portanto, se executarmos um aplicativo com JVM 13 e incluirmos dependências compiladas com uma versão mais antiga doJava Compiler (javac), a JVM pode considerar as dependências desatualizadas inválidas.
Portanto, ao vincular arquivos.class mais antigos com uma JVM mais recente,the JVM may throw a java.lang.VerifyError semelhante ao seguinte:
java.lang.VerifyError: Expecting a stackmap frame at branch target X
Exception Details:
Location:
com/example/example.Foo(Lcom/example/example/Bar:Baz;)Lcom/example/example/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
...
Existem duas maneiras de resolver esse problema:
-
Atualize as dependências para as versões compiladas com umjavac atualizado
-
Desativar verificação Java
3. Solução de Produção
A causa mais comum de um erro de verificação é vincular binários usando uma versão JVM mais recente compilada com uma versão mais antiga dejavac. Isso é mais comum quandodependencies have bytecode generated by tools such as Javassist, o que pode ter gerado bytecode desatualizado se a ferramenta estiver desatualizada.
Para resolver esse problema,update dependencies to aversion built using a JDK version that matches the JDK version used to build the application. Por exemplo, se criarmos um aplicativo usando o JDK 13, as dependências deverão ser construídas usando o JDK 13.
Para encontrar uma versão compatível, inspecioneBuild-Jdk emJAR Manifest file da dependência para garantir que corresponda à versão JDK usada para construir o aplicativo.
4. Solução de depuração e desenvolvimento
Ao depurar ou desenvolver um aplicativo, podemos desativar a verificação como uma solução rápida.
Não use esta solução para o código de produção.
Ao desativar a verificação, a JVM pode vincular códigos mal-intencionados ou defeituosos a nossos aplicativos, resultando em comprometimentos de segurança ou falhas quando executados.
Observe também que a partir do JDK 13,this solution has been deprecated, e não devemos esperar que essa solução funcione em versões futuras do Java. Desativar a verificação resultará no seguinte aviso:
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.
O mecanismo para desativar a verificação de bytecode varia de acordo com a forma como executamos nosso código.
4.1. Linha de comando
Para desativar a verificação na linha de comando, passe o sinalizadornoverify para o comandojava:
java -noverify Foo.class
Observe que-noverify is a shortcut for-Xverify:none e ambos podem ser usados alternadamente.
4.2. Maven
Para desativar a verificação em uma compilaçãoMaven, passe a sinalizaçãonoverify para qualquer plug-in desejado:
com.example.example
example-plugin
-noverify
4.3. Gradle
Para desativar a verificação em um buildGradle, passe o sinalizadornoverify para qualquer tarefa desejada:
someTask {
// ...
jvmArgs = jvmArgs << "-noverify"
}
5. Conclusão
Neste tutorial rápido, aprendemos por que a JVM executa a verificação de bytecode e o que causa o errojava.lang.VerifyError. Também exploramos duas soluções: uma de produção e outra de não produção.
Quando possível,use the latest versions of dependencies prefere desabilitar a verificação.