This PR solves two related bugs that are caused by events being delivered while 
the FX runtime is in the process of shutting down. These bugs are related 
enough that I think they need to be addressed at the same time. While debugging 
and developing the test, I saw one or the other or both in various test runs. 
The system test included with this program verifies that there is no crash and 
no exception, so will catch either failure mode.

This can happen when there is a full-screen window showing during shutdown on 
macOS, since full screen enter / exit uses a nested event loop that affects the 
order of operation. This could theoretically happen in other cases, thus the 
fix does not involve checking whether we are in full-screen or whether there is 
a nested event loop.

The fix does the following:

1. `GlassWindow+Overrides.m`: Check that the JVM is still running before 
calling the Java notification method in `windowDidResignKey` and 
`windowShouldClose`. This matches what is already done for other similar 
methods in this class. This is the fix for JDK-8335630.
2. `Window.java` and `View.java`: Check whether the Application instance is 
null in the event notification callbacks, and skip handling the event if it is. 
This is the fix for JDK-8299738.

Note that the fix for 2 is in platform-independent code. This should be fine, 
since we would want to skip the event handling callback on any other platform 
if it were done during shutdown, in order to avoid the ISE.

I have included a system test that passes on all platforms. On macOS, the test 
will fail without the fix and pass with the fix.

Details of the fix are below:

`Platform::exit` is called by the application to shutdown the JavaFX toolkit. 
The implementation of `Platform::exit` calls `Toolkit::exit` on the JavaFX 
Application thread, which in turn calls glass `Application::terminate` to shut 
it down. `Application::terminate` will close all the native windows, and call 
`finishTerminating` to terminate the native event loop and detach the thread 
from the JVM. This is asynchronous, at least on macOS, and will schedule the 
termination by posting a native event to the event loop.

on macOS 13, and sometimes on macOS 14, a Window or View event handler can be 
called between `Toolkit::exit`/`Application::terminate` (which sets the 
Toolkit's cached thread to null and the glass Application instance to null) and 
the JVM shutdown. This will make a JNI upcall to the appropriate Window or View 
`handleXxxxx` method, which will deliver it to the registered event handler. 
Because the Toolkit thread has been set to null, the "are we on the JavaFX 
Application thread" check will fail and it will throw an ISE. Since it can't 
usefully do anything anyway, we just want to skip handling it.

On macOS 14, `windowDidResignKey` can be called after the JVM is shutdown, 
causing an assertion print statement and then a crash when it tries to call a 
JNI method using a NULL `env` pointer. We need to use the 
`GET_MAIN_JENV_NOWARN` flavor of the macro to get the JNI `env`, and then check 
`env` for non-null.

NOTE: I intend to backport this to the `jfx23` stabilization branch for JavaFX 
23 after it is integrated into mainline.

-------------

Commit messages:
 - Revert "Debug prints"
 - Debug prints
 - 8335630: Crash if Platform::exit called with fullScreen Stage on macOS 14

Changes: https://git.openjdk.org/jfx/pull/1506/files
  Webrev: https://webrevs.openjdk.org/?repo=jfx&pr=1506&range=00
  Issue: https://bugs.openjdk.org/browse/JDK-8335630
  Stats: 157 lines in 4 files changed: 130 ins; 0 del; 27 mod
  Patch: https://git.openjdk.org/jfx/pull/1506.diff
  Fetch: git fetch https://git.openjdk.org/jfx.git pull/1506/head:pull/1506

PR: https://git.openjdk.org/jfx/pull/1506

Reply via email to