Saturday, November 23, 2024
Google search engine
HomeLanguagesJavaWhy java.lang.VerifyError Occurs in Java and How to Solve this?

Why java.lang.VerifyError Occurs in Java and How to Solve this?

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, a verification process is done on the .class files by the JVM.

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.

The VerifyError exists since the 1.0 version of Java.

The Structure of VerifyError:

Constructors

VerifyError()

This constructor creates an instance of the VerifyError class, setting null as its message.

VerifyError(String s)

This constructor creates an instance of the VerifyError class, using the specified string as message.  Here the class which threw the error is indicated through string argument.

The three most common reasons upon which this error may occur as follows:

Reason 1: “This error will be thrown whenever a class which is declared as final is extended.” 

Program:

Java




// Java program to show the occurrence
// of  java.lang.VerifyError
 
class B extends A {
 
    public static void main(String args[])
 
    {
 
        System.out.println("my super class name:-"
                           + myname);
    }
}
 
public class A
 
{
 
    static String myname = "A";
}


As you see if you compile these two programs and execute it, it must have to work fine without showing any error. Now after changing the class A as follows and compile it alone. 

final public class A
{
  static String myname="A";
}

Note that here we have recompiled the “class A” alone. Now if we execute the class B (class that contains main() method) then an error message like below will be thrown at run-time.

Exception in thread "main" java.lang.VerifyError: Cannot inherit from final class
       at java.lang.ClassLoader.defineClass1(Native Method)
       at java.lang.ClassLoader.defineClassCond(Unknown Source)
       at java.lang.ClassLoader.defineClass(Unknown Source)
       at java.security.SecureClassLoader.defineClass(Unknown Source)
       at java.net.URLClassLoader.defineClass(Unknown Source)
       at java.net.URLClassLoader.access$000(Unknown Source)
       at java.net.URLClassLoader$1.run(Unknown Source)
       at java.security.AccessController.doPrivileged(Native Method)
       at java.net.URLClassLoader.findClass(Unknown Source)
       at java.lang.ClassLoader.loadClass(Unknown Source)
       at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
       at java.lang.ClassLoader.loadClass(Unknown Source)
Could not find the main class: B.  

This error was caused because that we changed the definition of class TestClassA, but class TestClassB was compiled using an older version of the class TestClassA.

Reason 2: “Consider a class that extends another class before and if it no longer extends that class now, then this error may be thrown at run-time.”

Program:

Java




// Java program to show the occurrence
// of  java.lang.VerifyError
 
class C extends B {
    public static void main(String args[])
    {
        B b = new B();
        display(b);
    }
    public static void display(A a)
    {
        System.out.println(a.supername);
    }
}
 
class B extends A {
    String subname = "B";
}
 
public class A {
    String supername = "A";
}


Output

A

The above program will also work fine, but if class B is changed to no longer extend class A then error may get thrown. Now if we change the class B as follows , and “recompile it alone” , then class C will have no idea about the changes made in class B thus causing this error.

class B {
String subname="B";
}

Exception in thread “main” java.lang.VerifyError: (class: C, method: main signature: ([Ljava/lang/String;)V) Incompatible argument to function

Could not find the main class: C.  

Program will exit.

Reason 3: “If we try to override a method which is declared as final then also this error will be thrown”. Let us have classes A and B as follows:

Program:

Java




// Java program to show the occurrence
// of  java.lang.VerifyError
 
class B extends A
{
 
    public static void main(String args[])
 
    {
 
        A a = new A();
 
        a.display();
    }
 
    void display() { super.display(); }
}
 
public class A
{
    String supername = "A";
 
    void display()
 
    {
 
        System.out.println("My name is " + supername);
    }
}


In class A if the method display()  is changed to be of final and “recompile it alone”, then this verify error will be thrown if class B is executed since no other class can override this method.

Output:

Exception in thread "main" java.lang.VerifyError: class B overrides final method
display.()V
       at java.lang.ClassLoader.defineClass1(Native Method)
       at java.lang.ClassLoader.defineClassCond(Unknown Source)
       at java.lang.ClassLoader.defineClass(Unknown Source)
       at java.security.SecureClassLoader.defineClass(Unknown Source)
       at java.net.URLClassLoader.defineClass(Unknown Source)
       at java.net.URLClassLoader.access$000(Unknown Source)
       at java.net.URLClassLoader$1.run(Unknown Source)
       at java.security.AccessController.doPrivileged(Native Method)
       at java.net.URLClassLoader.findClass(Unknown Source)
       at java.lang.ClassLoader.loadClass(Unknown Source)
       at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
       at java.lang.ClassLoader.loadClass(Unknown Source)
Could not find the main class: B.  Program will exit.

Here you could have noticed that this verifies Error is thrown because we have recompiled only the edited class” and not all the classes as a whole. So you may think that this error can be easily identified if you recompile all the classes as a whole by recompiling the class which contains the main() method. Of course, it is true but there are certain situations in which you cannot be able to identify this error at Compile time, which is mainly because of using two different versions of third-party libraries in your application. 

How to deal with the VerifyError?

In order to avoid the VerifyError, you must compile all your classes using the same version of Java. Also, once a change is done to a class, then make sure that you re-compile your project from scratch. Finally, if your application makes use of external libraries, verify that you use the appropriate version of every library and of course, consult the corresponding javadocs, in order to be sure that everything is correct.

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

RELATED ARTICLES

Most Popular

Recent Comments