Handling Errors in Java

Native methods are a significant security risk to Java programs. The C runtime system has no protection against array bounds errors, indirection through bad pointers, and so on. It is particularly important that programmers of native methods handle all error conditions to preserve the integrity of the Java platform. In particular, when your native method diagnoses a problem it cannot handle, it should report this problem to the Java virtual machine.

Normally, you would throw an exception in this situation. However, C has no exceptions. Instead, you must call the Throw or ThrowNew function to create a new exception object. When the native method exits, the Java virtual machine throws that exception.

To use the Throw function, call NewObject to create an object of a subtype of Throwable. For example, here we allocate an EOFException object and throw it:

jclass class_EOFException = (*env)->FindClass(env, “java/io/EOFException”);

jmethodID id_EOFException = (*env)->GetMethodID(env, class_EOFException, “<init>”, “()V”);

/* ID of no-argument constructor */

jthrowable obj_exc = (*env)->NewObject(env, class_EOFException, id_EOFException); (*env)->Throw(env, obj_exc);

It is usually more convenient to call ThrowNew, which constructs an exception object, given a class and a “modified UTF-8” byte sequence.

(*env)->ThrowNew(env, (*env)->FindClass(env, “java/io/EOFException”),

“Unexpected end of file”);

Both Throw and ThrowNew merely post the exception; they do not interrupt the control flow of the native method. Only when the method returns does the Java virtual machine throw the exception. Therefore, every call to Throw and ThrowNew should be immediately followed by a return statement.

Normally, native code need not be concerned with catching Java exceptions. However, when a native method calls a Java method, that method might throw an exception. Moreover, a number of the JNI functions throw exceptions as well. For example, SetObjectArrayElement throws an ArrayIndexOutOfBoundsException if the index is out of bounds, and an ArrayStoreException if the class of the stored object is not a subclass of the element class of the array. In situations like these, a native method should call the ExceptionOccurred method to determine whether an exception has been thrown. The call

jthrowable obj_exc = (*env)->ExceptionOccurred(env);

returns NULL if no exception is pending, or a reference to the current exception object. If you just want to check whether an exception has been thrown, without obtaining a reference to the exception object, use

jboolean occurred = (*env)->ExceptionCheck(env);

Normally, a native method should simply return when an exception has occurred so that the virtual machine can propagate it to the Java code. However, a native method may analyze the exception object to determine if it can handle the exception. If it can, then the function

(*env)->ExceptionClear(env);

must be called to turn off the exception.

In our next example, we implement the fprint native method with all the paranoia appropriate for a native method. Here are the exceptions that we throw:

  • A NullPointerException if the format string is NULL
  • An IllegalArgumentException if the format string doesn’t contain a % specifier that is appropriate for printing a double
  • An OutOfMemoryError if the call to malloc fails

Finally, to demonstrate how to check for an exception when calling a Java method from a native method, we send the string to the stream, a character at a time, and call ExceptionOccurred after each call. Listing 12.17 shows the code for the native method, and Listing 12.18 shows the definition of the class containing the native method. Notice that the native method does not imme­diately terminate when an exception occurs in the call to PrintWriter.print—it first frees the cstr buffer. When the native method returns, the virtual machine again raises the exception. The test program in Listing 12.19 demonstrates how the native method throws an exception when the formatting string is not valid.

Source: Horstmann Cay S. (2019), Core Java. Volume II – Advanced Features, Pearson; 11th edition.

Leave a Reply

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