Java Top

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE

1. Introduction

In this tutorial, we'll look at the cause of java.lang.VerifyError errors and multiple ways to avoid it.

2. Cause

The Java Virtual Machine (JVM) distrusts all loaded bytecode as a core tenet of the Java Security Model. During runtime, the JVM will load .class files and attempt to link them together to form an executable — but the validity of these loaded .class files is unknown.

To ensure that the loaded .class files do not pose a threat to the final executable, the JVM performs verification on the .class files. Additionally, the JVM ensures that binaries are well-formed. For example, the JVM will verify classes do not subtype final classes.

In many cases, verification fails on valid, non-malicious bytecode because a newer version of Java has a stricter verification process than older versions. For example, JDK 13 may have added a verification step that was not enforced in JDK 7. Thus, if we run an application with JVM 13 and include dependencies compiled with an older version of the Java Compiler (javac), the JVM may consider the outdated dependencies to be invalid.

Thus, when linking older .class files with a newer JVM, the JVM may throw a java.lang.VerifyError similar to the following:

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

There are two ways to solve this problem:

  • Update dependencies to versions compiled with an updated javac
  • Disable Java verification

3. Production Solution

The most common cause of a verification error is linking binaries using a newer JVM version compiled with an older version of javac. This is more common when dependencies have bytecode generated by tools such as Javassist, which may have generated outdated bytecode if the tool is outdated.

To resolve this issue, update dependencies to a version built using a JDK version that matches the JDK version used to build the application. For example, if we build an application using JDK 13, the dependencies should be built using JDK 13.

To find a compatible version, inspect the Build-Jdk in the JAR Manifest file of the dependency to ensure it matches the JDK version used to build the application.

4. Debugging & Development Solution

When debugging or developing an application, we can disable verification as a quick-fix.

Do not use this solution for production code.

By disabling verification, the JVM can link malicious or faulty code to our applications, resulting in security compromises or crashes when executed.

Also note that as of JDK 13, this solution has been deprecated, and we should not expect this solution to work in future Java releases. Disabling verification will result in the following warning:

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.

The mechanism for disabling bytecode verification varies based on how we run our code.

4.1. Command Line

To disable verification on the command line, pass the noverify flag to the java command:

java -noverify Foo.class

Note that -noverify is a shortcut for-Xverify:none and both can be used interchangeably.

4.2. Maven

To disable verification in a Maven build, pass the noverify flag to any desired plugin:

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

4.3. Gradle

To disable verification in a Gradle build, pass the noverify flag to any desired task:

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

5. Conclusion

In this quick tutorial, we learned why the JVM performs bytecode verification and what causes the java.lang.VerifyError error. We also explored two solutions: A production one and a non-production one.

When possible, use the latest versions of dependencies rather than disabling verification.

Java bottom

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE

Leave a Reply

avatar
  Subscribe  
Notify of