Using setjmp/longjmp from JNA
TLDR: I didn’t think it would work, and it didn’t.
Today I had a goal to call an established C library from Java, but it uses setjmp
and longjmp
for error reporting.
I had been hoping/planning to use Java Native Access to interact with the libraries. This is just a simple hobby project, so I want to keep it as simple as I realistically can. That means I don’t want to add a C build step to my project at all, not to mention having the build target multiple OS platforms and CPU architectures.
But I didn’t really expect setjmp
and longjmp
to work in Java. I have no idea what the JVM does with the execution environment and I expected longjmp
would interfere with it in a way that would very probably corrupt the JVM’s state.
I tried it anyway. It didn’t work. The program crashed with SIGABRT after longjmp
(running on Linux).
I encountered some things I found a little more interesting than just “it doesn’t work”, though:
jmp_buf’s size isn’t predictable
setjmp
requires that you allocate a jmp_buf
to store the environment in.
jmp_buf
is defined in the system setjmp.h
. On my 64-bit Linux system, sizeof(jmp_buf) == 200
, and it’s defined as a 1-element array containing a struct, so it can be allocated easily then passed by reference.
I dug into setjmp.h
first to understand it more, and realized the size of jmp_buf
isn’t really predictable:
- It varies by architecture even with the same C library, and
- It’s not specified by the standard that it even has to be a struct or anything. It could just be a handle or whatever.
setjmp could be a macro
The standard doesn’t specify whether setjmp
is a function or macro. JNA can only call functions, since macros are inlined by the compiler at build time.
(I didn’t check how it’s implemented in other C libraries, like MSVCRT on Windows or libSystem on macOS.)
Not exactly related, but I also happened to call fflush(stdout)
from Java. It turns out that stdout
is actually specified in C89/C99 to be a macro. In glibc, it’s also exported as extern FILE *stdout
so I was able to use that, but then my code would not conform to standard.
I guess I’m gonna have to write a C adapter library that’s more Java-friendly.