RFR(S): Use Vectored Exception Handling on Windows

Ludovic Henry luhenry at microsoft.com
Thu Jun 25 21:36:31 UTC 2020

Following our offline discussion, we are going to _experiment_ using VEH in the following manner:
 - Use AddVectoredExceptionHandler to cover the cases triggered by Java (like safepoint-polling or various stubs like arraycopy) but do not deal with crashes in that handler
 - Add an Unhandled Exception Handler that deals with the cases that are neither knowingly triggered by Java code nor covered by any external libraries' structured or vectored exception handlers.

For this experiment to be more successful, I'll also look into developing tests that cover these cases and add them to the appropriate OpenJDK test suite.

I'll update this thread as I go along this experiment, sharing any result I get and any test I develop.

As I'm currently focused on the support for Windows-aarch64, I cannot guarantee I'll have time to look at that over the next few days.

From: hotspot-runtime-dev <hotspot-runtime-dev-bounces at openjdk.java.net> on behalf of Ludovic Henry <luhenry at microsoft.com>
Sent: Friday, June 19, 2020 09:24
To: Bob Vandette
Cc: hotspot-runtime-dev at openjdk.java.net
Subject: RE: RFR(S): Use Vectored Exception Handling on Windows

Hi Bob,

For 1. and 2., these are very similar to issues encountered with signals as well, and VEH already supports the concept of “signal chaining” out of the box. If we want to be extremely specific, we can replace the use of RltAddFunctionTable with VEH and a check that the PC is in a certain code area (the code cache or the AOT libraries), and simply return EXCEPTION_CONTINUE_SEARCH otherwise. That would simulate the use of RltAddFunctionTable and remove the need for SEH in the most problematic case.

For 3., it is definitely something we can discuss with the Windows team directly, and figure out a potential workaround. I’ll contact you to setup a call if you’re interested.


From: Bob Vandette <bob.vandette at oracle.com>
Sent: Friday, June 19, 2020 8:45 AM
To: Ludovic Henry <luhenry at microsoft.com>
Cc: hotspot-runtime-dev at openjdk.java.net
Subject: Re: RFR(S): Use Vectored Exception Handling on Windows

Windows Vectored Exceptions seems like a perfect solution for JVMs exception handling since its
similar to Linux signals but they just different enough to cause problems.

I first used VEH when I did the Windows Itanium port many many years ago.  It seemed to work
for a while until we started testing.  Heres the bug that was used in JDK 1.5 to eliminate the use of VEH.


We are currently using VEH on Windows for AOT generated code.  This is a temporary fix
that we hope to rectify.  Here’s the bug I filed for this work:


The main problems with VEH are:

1. If JNI code uses VEH, they need to know to filter out and pass exceptions that are meant for the JVM.
2. If JNI code uses SEH, the JVM will get the exception first and will need to determine if it should handle this exception or not.
3. Windows DLLs use SEH and there are active exceptions being generated causing the same problem as #2.


On Jun 19, 2020, at 11:22 AM, Ludovic Henry <luhenry at microsoft.com<mailto:luhenry at microsoft.com>> wrote:


First, some context and definitions:
- when talking about exception here, I'm talking about Win32 exception which are equivalent to signals on Linux and other Unix, I am _not_ talking about Java exceptions.
- an explanation of an _exception filter_ can be found at https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fcpp%2Fcpp%2Fwriting-an-exception-filter%3Fview%3Dvs-2019&data=02%7C01%7Cluhenry%40microsoft.com%7Cb3166cfe2f734b9bbadb08d8146d8d6c%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637281808052331187&sdata=99InoVbN3VLa9%2FPcoy7VXkXDrzGc%2Bc4M5XUt5X0vRyI%3D&reserved=0<https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fcpp%2Fcpp%2Fwriting-an-exception-filter%3Fview%3Dvs-2019&data=02%7C01%7Cluhenry%40microsoft.com%7Cb3166cfe2f734b9bbadb08d8146d8d6c%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637281808052331187&sdata=99InoVbN3VLa9%2FPcoy7VXkXDrzGc%2Bc4M5XUt5X0vRyI%3D&reserved=0>. There is only a limited concept of that in Java with type-based exception filter (ex: `try { ... } catch (IOException ioe) { ... } catch (Throwable t) { ... }`).
- in Win32, there exist two exception handling mechanism:
 - Structured Exception Handling: the historical one, based on `__try {} __except (...) {}`
 - Vectored Exception Handling: introduced in Windows XP / Windows Server 2003, much more similar to signals on Linux

These exception handling mechanisms are used to catch any exceptions like Access Violation, Stack Overflow, Divide by Zero, Overflow, and more. These exceptions are equivalent to signal on Linux and are then core to many mechanisms in the OpenJDK.

Today, the OpenJDK uses Structured Exception Handling to catch such exceptions, creating several requirements. First, all code that might trigger an exception on purpose (like a Access Violation / SIGSEGV in the arraycopy stub), needs to be wrapped up in a __try / __except. Because it's not feasible to wrap every single instance of such code, these __try / __except are put at the top-level most function of any thread started by the runtime. Second, for code generated by Hotspot, `RtlAddFunctionTable` is used to simulate the use of __try / __except for a specific code area. This function needs platform specific code with the generation of  a trampoline that calls the exception filter declared in the runtime. It's also meant to be used as a one to one mapping with try / catch in user code, and not as a "catch all the exceptions in this code area". Third, Structured Exception Handling expects to be able to unwind the stack. However, because Hotspot doesn't guarantee the usage of the platform-specific ABI internally, the platform-specific unwinder might break. Hotspot's usage of `RtlAddFunctionTable` for the code cache relies on the assumption that Structured Exception Handling never tries to unwind the stack (which it would fail to do because of the different ABI) before calling the registered exception filter.

Discussing that with Windows Kernel maintainers, this approach is highly discouraged, considered brittle, and the better solution is Vectored Exception Handling. Vectored Exception Handling is conceptually much more similar to signal / sigaction on Linux and other Unix systems. It will catch all exceptions happening across the process, and no __try / __except will be required. It also removes the requirement to call `RtlAddFunctionTable`.  The exception filter then behaves like a signal handler with the possibility to modify the registers at will, modifying the PC to step over an instruction after an expected Access Violation for example. Vectored Exception Handling is also already used for AOT code.

The changes can be found at https://nam06.safelinks.protection.outlook.com/?url=http:%2F%2Fcr.openjdk.java.net%2F~burban%2Fludovic_vecexc%2F&data=02%7C01%7Cluhenry%40microsoft.com%7Cb3166cfe2f734b9bbadb08d8146d8d6c%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637281808052331187&sdata=AGabt7f3tpPQPbVrjGMqNE0kjzqZTkWf41Fn3n7KZeU%3D&reserved=0<https://nam06.safelinks.protection.outlook.com/?url=http:%2F%2Fcr.openjdk.java.net%2F~burban%2Fludovic_vecexc%2F&data=02%7C01%7Cluhenry%40microsoft.com%7Cb3166cfe2f734b9bbadb08d8146d8d6c%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637281808052341177&sdata=OUt0ZjIrZEUWN%2BK2Hi5gpTnYVWLGMURK3VV52QG6Q6A%3D&reserved=0>. As I am not an author, I have not created a corresponding bug in JBS.

Thank you, and looking forward for your feedback!


More information about the hotspot-runtime-dev mailing list