recipe № 015

handling SIGSEGV/SIGBUS in JNI code (stop JVM from crashing)

In this sample, I will show you how to prevent JVM from crashing whenever SIGSEGV (Linux) or SIGBUS (OS X) occurs.
This sample will require some low level coding, but I hope you will be able to follow it.
After you complete this tutorial, you should end up with the layout similar to this one:

In this sample, we have two Java classes that call the same native function – riskyCode(). SigSegv handles the SIGSEGV/SIGBUS and SigSegvNoHandler doesn’t care about that.

First code – SigSegv.java – is the code where we call callRiskyCode function (native code). This function makes few things (make sure to check C source). First of all, it sets signal handler, second, it calls the code – riskyCode – third, it either throws exception (in case of error) or sets default handlers (in case of successful execution). Remember, SigSegv.java simply calls native code that does all the tricky things.

As for the SigSegvNoHandler.java we do similar thing. But in this case, we just call callRiskyCodeNoHandler (native code) that calls the buggy code but it doesn’t care about handlers. This is the place where JVM will crash with famous hs_er file.

After we create header files with JNI signatures, we will get following files. Each of them defines one function.

and

These files declare methods that will be called from Java.

The mechanism is very simple. The C code will call riskyCode function two different ways. First time, it will wrap the call with signal handlers. Second time, it will call it as is – no signal handling or whatsoever. If you are completely unfamiliar with signal handlers, make sure to check the info checking man pages – man signal. In our case, we will be interested in two signals (underlined).

(for the full list of signals take a look at Appendix A)

The point here is that for catching illegal access to memory OS X uses SIGBUS while Linux uses SIGSEGV. So, we handle both signals in the code. As for the implementation, we can put everything inside a single file.

After we compile everything

We get he library and compiled Java code. Now, we can run it

As you can see, first call caught the SIGSEGV/SIGBUS and we can see both, message from signal handler (Hello from handler) and Exception related message from Java code (Call to callRiskyCode() finished with exception). In second case, where no signals are caught, we can see that JVM crashes after signal is raised.