Funneling Objects through void*
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Thu Jun 15 23:08:07 UTC 2023
Hi,
I wanted to reply on this point, since this is also an important one.
On 15/06/2023 20:30, Johannes Kuhn wrote:
> WRT Exceptions. I did notice that throwing an exception in an upcall
> crashes the JVM. Not so great. Means I need to do some extra work
> catching them, checking for pending exceptions (there should be none,
> but you never know) and return the appropriate "abort enumerating"
> constant.
>
> Not sure if this could be improved by specifying an "exception return
> value" when creating the upcall and then rethrow the exception when
> the underlying downcall returns.
So, what should happen when an upcall fails with exceptional state? This
is a question we asked ourselves many (many) times. There are many
options, but we seem to always keep coming back to the same answer. It
might be worth, nevertheless, expand a bit on what the rationale behind
the current decision is.
The reason we terminate the JVM when there's an unhandled exception in
an upcall is that if we didn't, we would have to pop all the native
frames until we reached some Java frame, and then rethrow the exception
there. While this gives a relatively intuitive behavior (the exception
thrown in the upcall can be caught by the code that initiated the
downcall to which the upcall was passed), there is a biggie issue: what
happens to the native code that was popped? We were, after all, in the
middle of executing code inside some function. Perhaps the function
needed, after the upcall, to reset some state for the next iteration.
Sadly, by simply stepping over the native code, we now have left the
native library in an inconsistent state. If you catch the exception and
try to call the same function again, there's no way to predict what's
going to happen.
The C language (with the notable exception of Windows [1]) doesn't have
a concept of stack unwinding (unlike C++). That said, stack unwinding is
extremely platform/compiler-dependent. In some platfroms (notably,
Windows) there is a clearly supported API to do it, in some others less
so (Linux does have libunwind [2]). But even if we did unwinding
correctly, while that might save C++ code that got caught in the middle
of an exception, that would still do nothing for C code.
Overall, there's no silver bullet here. To recap:
* Admit that we don't know how to proceed, and terminate the JVM (what
we do today);
* Pop all the native frames, leaving the native library in some
undefined state;
* Attempt unwinding (assuming we can in all platforms), rescuing some
C++ cases, but still leaving C code in undefined state.
What we do today is blunt, but honest. Other options involving
popping/unwinding are possible, but the reality is, the underlying
native library has potential to misbehave from the point at which the
exception occurred.
In some APIs (e.g. libclang cursor visitors [3] work like that), an
upcall can return a value which says "please visit no more". If this
idiom was frequent enough, perhaps we could provide an upcall Linker
option which defines a "fallback" return value, to be used in case of
exceptions. For primitive returns that's a possibility, but if the
return value is a pointer or a struct things are more difficult: the
fallback segment could no longer be alive by the time it is accessd from
the native code surrounding the upcall (which would lead, again, to a
crash).
Overall, whenever we discussed this, the general feeling was always that
there's no "right" or "wrong" answer: handling exceptions thrown from
upcalls is a matter of "choosing the right policy" for the particular
kind of upcall one needs to define. Sometimes it might be convenient to
"return 0", sometimes to just crash, other times to pop all native
frames, etc.
Cheers
Maurizio
[1] -
https://learn.microsoft.com/en-us/cpp/cpp/structured-exception-handling-c-cpp?view=msvc-170
[2] - https://github.com/libunwind/libunwind
[3] -
https://clang.llvm.org/doxygen/group__CINDEX__CURSOR__TRAVERSAL.html#ga99a9058656e696b622fbefaf5207d715
More information about the panama-dev
mailing list