Class VerifyError in Java

Class VerifyError in Java

VerifyError is thrown from an application when verifier detects that the class file through well-formed, contains some sort of internal inconsistency or security problems.

In other words, it signals that bytecode verification could not be passed for a class.

A VerifyError is thrown when the byte-code verifier detects that a class file, though well-formed, contains some sort of internal inconsistency or security problem.

As part of loading the byte-codes for a class, the Java virtual machine may run the .class file through the byte-code verifier. The default mode of the virtual machine causes it not to verify classes that are found locally, however. Thus, after compiling an applet and running it locally, we may still get a VerifyError when we put it on a web server.

The class file verifiers

Along with class loader, the class file verifier verifies the class that is being loaded has

  1. A proper internal structure
  2. A consistent structure.

In case the class file verifier finds any issue with the class file that is being loaded, throws an exception.

For a Java Virtual Machine, it is very tough to understand if the loaded class is generated by a proper Java compiler or generated by the hacker as the class file is a sequence of bytes.

To protect from this threat, java run time invokes the class five verifier to be sure the types that are defined are really safe to use. It also verifies the integrity of the imported byte codes.

The class file verifier operates in four different passes.

Pass I – Internal structure checking and confirm if the byte codes are safe the parse.

Pass II & III – Checks the semantics of Java language and checks the integrity of the byte codes.

Pass IV – The symbolic references are resolved during the dynamic linking process.

Pass One – The Structural Checks on the Class File –

The verified thus performs several different checks during this pass. Like –

  1. Every class must start with four bytes magic number (OxCAFEBABE).

This check segregates if the byte code represents a valid class file or it is a damaged one or not a class file altogether.

  1. It checks the major and minor version numbers, present in the class file. This major and minor number should be in the supported range to the Java Virtual Machine implementation.
  2. The class file verifier also checks if the file has been truncated or enhanced with extra trailing bytes. The verifier checks these values from the type and length attributes defined in the class file.
READ  Abstract Class ResourceBundle in Java

Pass Two: Semantic checks on the Type Data

During phase – II, the verifier does not check the byte codes and any other types. The file verifier looks at the individual components to check if they are well-formed instances of their types (components).

The well-formed means one or all of the following –

  1. Adhere to context-free grammar.
  2. Method descriptor is a well-formed string.
  3. The class adheres to certain constraints (as per Java programming language).
  4. The final classes are not subclassed and final methods are not overridden.
  5. All classes except object class have a parent class.
  6. All constant entries are valid and all indexes into the constant pool refer to the correct type of the constant pool entry.

Now, one may say, these are jobs of a java compiler, but before execution, the Java Virtual Machine ensures that the stream of bytes is actually valid one. It also checks if all rules are followed before execution.

Pass Three: Byte code Verification

During this phase, java Virtual Machine performs a data flow analysis on the streams of byte codes (mostly represents the methods of the class).

The byte code streams are a series of one-byte instructions known as opcodes. Each opcode is followed by one or many operands (They are the metadata for the opcode to perform correctly). The execution of opcode is performed by threads. Every thread has its own stack (made with discrete framed). Each method call gets its own frame. A frame is defined as a section of memory. All local variables and results of computation intermediately are stored in the frame. Now the section of frame where method stores intermediate result is called the method’s operand stack. An opcode or its operand, when needed, looks for this operand stack or the local variables of the method’s frame.

The byte code verifier makes sure inspective of the path of the class the stack is filled up with opcode. Of certain type in the byte code stream, the operand stack also contains the same number and types of items. The other thing it checks is the local variable. It ensures that no local variable is accessed before it contains a value. It means it explicitly checks that the fields of the class are always assigned some values of the proper type. It also checks if the methods are also invoked with the correct number and types of arguments.

READ  Abstract Class HttpURLConnection in Java

Beside these bytes code verifier also checks opcode is valid, the value of the opcode are valid too!

Apart from these, we can find another type of checks if we see the check xxx methods.

However, byte code verifier does not check the safety of the code. This is done to resolve the classic halting program.

Halting program says we cannot write a program that can determine whether any program fed into it as input will halt when it is being executed. The undecidable property of a code tells if the program will really Hall or not.

The uncertainty of the halting problem is resolved by byte code verifier in the above manner.

Pass Four- Verification of Symbolic references

In this phase, all symbolic references present in the class are resolved. It is done with the help of dynamic linking. First Java Virtual Machine checks if the references made in the class are correct. Now as the references, called out in the class file are external to the current class, Java Virtual Machine needs to check that file as well. Most likely, the Java Virtual Machine will defer the loading process of the new classification until it is needed (as late as possible).

During discovery of class (external), if it does not find, JVM immediately does raise No Class Def Found Error. It tries to load the referenced class by resolving symbolic references.

A symbolic reference is a string made of characters that provide the Java Virtual Machine with the name and meta (information about the object) data of the item. This metadata is enough to identify uniquely about the class, fields, methods, method descriptor etc.

Dynamic linking is a process of resolving symbolic references into direct references.

The Java Virtual Machine performs the following tasks in the process –

  1. Finding the class being referenced (load immediately or deferred as necessary).
  2. Resolve the symbolic references to direct references (A pointer of offset to the class, method, method descriptor etc).
  • JVM remembers the references for further usage and speeds up the process.

Now after all attempts to make sure if the reference is valid the reference class still cannot be loaded then the class verifier throws Class Not Found Error. If the symbolic reference from the class does not match methods in the referenced class JVM throws an error called – No Such Method Error.

READ  5 Best Facts: Static and Non Static Inner Class in Java With Easy Examples

These four passes are required to test the security integrity and binary compatibility. They are done in a phased manner to ensure the compatibility is intact. If in case, the compiler does not recompile a class or a package or a dependent class (maybe our own or borrowing someone’s class or package), it is impossible for us to check the compatibility during our compilation process. But Java Virtual Machine needs to make sure, the classes and dependent classes are compatible.

In practice, this situation happens when we update our libraries with a newer version. These rules of checking binary compatibility are listed in Java Language Specification (JLS). They tell what can be changed, added or deleted in a class that does not break binary compatibility of the existing classes.

Example – If we add a new method into a class and do not remove an existing one (If it is used by others) is binary compatible.

The Java Virtual Machine also performs the following tasks –

  1. Type safe reference casting.
  2. Structured memory access (No pointer arithmetic).
  3. Automatic Garbage Collection.
  4. Check the null references.
  5. Automatic array bounds checking.
  6. Backup for memory access.
  7. Dynamic selection of memory where the runtime execution puts data.
  8. Dynamic and unpredictable data structure to store data.
  9. Provide security layer over native methods.
  10. Proper and robust exception handling to ensure the exceptions or errors handled properly and the main thread keeps execution.

The structure of the class VerifyError is given as:

public class java.lang.VerifyError extends java.lang.LinkageError{
//constructor
public VerifyError();//constructs an empty VerifyError object that is an object with no message specified.
public VerifyError(String message);//constructs an VerifyError object with the message specified.}

The class VerifyError also inherits methods from class Object and Throwable.

From Object classFrom Throwable class
clone()fillInStackTrace()
getClass()getMessage()
notify()printStackTrace()
wait()printStackTrace(PrintWriter)
wait(long, int)getLocalizedMessage()
wait(long)printStackTrace(PrintStream)
equals(Object)
toString()
finalize()
hashCode()
notifyAll()

Share and Enjoy !

Leave a Reply

Your email address will not be published. Required fields are marked *