Causas e Prevenção de java.lang.VerifyError

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.