Yes, thank you Christopher for providing a reproducible test case!

I was able to trigger the problem on my Mac on the first try. Since I’m using a 
modified version of JavaFX the system didn’t crash but instead hit a Java stack 
overflow error and produced a very long stack trace.

At least on the Mac the problem seems to be that you’re trying to pop an Alert 
containing a long stack trace. While trying to adjust the Alert’s bounds JavaFX 
is throwing another exception but I’m not sure why. I’ll continue to look into 
it.

Thanks again,
Martin

> On Mar 25, 2025, at 12:16 PM, Andy Goryachev <andy.goryac...@oracle.com> 
> wrote:
> 
> Thank you, Christopher, for clarification!
>  
> Personally, I would consider this to be a problem with the application 
> design: the code should limit the number of alerts shown to the user.  Do you 
> really want the user to click through hundreds of alerts?
>  
> Nevertheless, you are right about the need for the platform to gracefully 
> handle the case of too many nested event loops - by throwing an exception 
> with a meaningful message, as Martin proposed in 
> https://github.com/openjdk/jfx/pull/1741
>  
> Cheers,
> -andy
>  
>  
>  
> From: Christopher Schnick <crschn...@xpipe.io>
> Date: Tuesday, March 25, 2025 at 11:52
> To: Andy Goryachev <andy.goryac...@oracle.com>
> Cc: OpenJFX <openjfx-dev@openjdk.org>
> Subject: Re: [External] : Re: JVM crashes on macOS when entering too many 
> nested event loops
> 
> Hey Andy,
> 
> so I think I was able to reproduce this issue for our application.
> 
> There are two main factors how this can happen:
> - We use an alert-based error reporter, meaning that we have a default 
> uncaught exception handler set for all threads which will showAndWait an 
> Alert with the exception message
> - As I reported yesterday with 
> https://mail.openjdk.org/pipermail/openjfx-dev/2025-March/052963.html, there 
> are some rare exceptions that can occur in a normal event loop without 
> interference of the application, probably because of a small bug in the 
> bounds calculation code
> 
> If you combine these two factors, you will end up with an infinite loop of 
> the showAndWait entering a nested event loop, the event loop throwing an 
> internal exception, and the uncaught exception handler starting the same loop 
> with another alert. I don't think this is a bad implementation from our side, 
> the only thing that we can improve is to maybe check how deep the uncaught 
> exception loop is in to prevent this from occurring indefinitely. But I would 
> argue this can happen to any application. Here is a sample code, based on the 
> reproducer from the OutOfBounds report from yesterday:
> 
> import javafx.application.Application;
> import javafx.application.Platform;
> import javafx.scene.Scene;
> import javafx.scene.control.Alert;
> import javafx.scene.control.Button;
> import javafx.scene.layout.Region;
> import javafx.scene.layout.StackPane;
> import javafx.scene.layout.VBox;
> import javafx.stage.Stage;
>  
> import java.io.IOException;
> import java.util.Arrays;
>  
> public class ParentBoundsBug extends Application {
>  
>     @Override
>     public void start(Stage stage) throws IOException {
>         Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
>             throwable.printStackTrace();
>  
>             if (Platform.isFxApplicationThread()) {
>                 var alert = new Alert(Alert.AlertType.ERROR);
>                 alert.setHeaderText(throwable.getMessage());
>                 
> alert.setContentText(Arrays.toString(throwable.getStackTrace()));
>                 alert.showAndWait();
>             } else {
>                 // Do some other error handling for non-platform threads
>                 // Probably just show the alert with a runLater()
>  
>                 // For this example, there are no exceptions outside the 
> platform thread
>             }
>         });
>  
>         // Run delayed as Application::reportException will only be called 
> for exceptions
>         // after the application has started
>         Platform.runLater(() -> {
>             Scene scene = new Scene(createContent(), 640, 480);
>             stage.setScene(scene);
>             stage.show();
>             stage.centerOnScreen();
>         });
>     }
>  
>     private Region createContent() {
>         var b1 = new Button("Click me!");
>         var b2 = new Button("Click me!");
>         var vbox = new VBox(b1, b2);
>         b1.boundsInParentProperty().addListener((observable, oldValue, 
> newValue) -> {
>             vbox.setVisible(!vbox.isVisible());
>         });
>         b2.boundsInParentProperty().addListener((observable, oldValue, 
> newValue) -> {
>             vbox.setVisible(!vbox.isVisible());
>         });
>         vbox.boundsInParentProperty().addListener((observable, oldValue, 
> newValue) -> {
>             vbox.setVisible(!vbox.isVisible());
>         });
>  
>         var stack = new StackPane(vbox, new StackPane());
>         stack.boundsInParentProperty().addListener((observable, oldValue, 
> newValue) -> {
>             vbox.setVisible(!vbox.isVisible());
>         });
>         return stack;
>     }
>  
>     public static void main(String[] args) {
>         launch();
>     }
> }
> 
> If the same OutOfBounds exception from the reported I linked happens in the 
> bounds calculation, which happens approximately 1/5 runs for me, this 
> application will enter new event loops until it crashes. If the OutOfBounds 
> doesn't trigger, it will just throw a StackOverflow but won't continue the 
> infinite loop of nested event loops. So for the reproducer it is important to 
> try a few times until you get the described OutOfBounds.
> 
> I attached the stacktrace of how this fails. The initial StackOverflow causes 
> infinitely many following exceptions in the nested event loop.
> 
> Best
> Christopher Schnick
> 
> On 25/03/2025 18:28, Andy Goryachev wrote:
> Dear Christopher:
>  
> Were you able to root cause why your application enters that many nested 
> event loops?
>  
> I believe a well-behaved application should never experience that, unless 
> there is some design flaw or a bug.
>  
> -andy
>  
>  
> From: Christopher Schnick <crschn...@xpipe.io> <mailto:crschn...@xpipe.io>
> Date: Monday, March 10, 2025 at 19:45
> To: Andy Goryachev <andy.goryac...@oracle.com> 
> <mailto:andy.goryac...@oracle.com>
> Subject: [External] : Re: JVM crashes on macOS when entering too many nested 
> event loops
> 
> Our code and some libraries do enter some nested event loops at a few places 
> when it makes sense, but we didn't do anything to explicitly provoke this, 
> this occurred naturally in our application. So it would be nice if JavaFX 
> could somehow guard against this, especially since crashing the JVM is 
> probably the worst thing that can happen.
> 
> I looked at the documentation, but it seems like the public API at 
> Platform::enterNestedEventLoop does not mention this.
> From my understanding, the method Platform::canStartNestedEventLoop is 
> potentially the right method to indicate to the caller that the limit is 
> close by returning false.
> And even if something like an exception is thrown when a nested event loop is 
> started while it is close to the limit, that would still be much better than 
> a direct crash.
> 
> Best
> Christopher Schnick
> 
> On 10/03/2025 18:51, Andy Goryachev wrote:
> This looks to me like it might be hitting the (native) thread stack size 
> limit.
>  
> c.s.glass.ui.Application::enterNestedEventLoop() even warns about it:
>  
>      * An application may enter several nested loops recursively. There's no
>      * limit of recursion other than that imposed by the native stack size.
>  
>  
> -andy
>  
>  
>  
> From: openjfx-dev <openjfx-dev-r...@openjdk.org> 
> <mailto:openjfx-dev-r...@openjdk.org> on behalf of Martin Fox 
> <martinfox...@gmail.com> <mailto:martinfox...@gmail.com>
> Date: Monday, March 10, 2025 at 10:10
> To: Christopher Schnick <crschn...@xpipe.io> <mailto:crschn...@xpipe.io>
> Cc: OpenJFX <openjfx-dev@openjdk.org> <mailto:openjfx-dev@openjdk.org>
> Subject: Re: JVM crashes on macOS when entering too many nested event loops
> 
> Hi Christopher,
> 
> I was able to reproduce this crash. I wrote a small routine that recursively 
> calls itself in a runLater block and then enters a nested event loop. The 
> program crashes when creating loop 254. I’m not sure where that limit comes 
> from so it’s possible that consuming some other system resource could lower 
> it. I couldn’t see any good way to determine how many loops are active by 
> looking at the crash report since it doesn’t show the entire call stack.
> I did a quick trial on Linux and was able to create a lot more loops (over 
> 600) but then started seeing erratic behavior and errors coming from the Java 
> VM. The behavior was variable unlike on the Mac which always crashes when 
> creating loop 254.
> 
> Martin
> 
> > On Mar 7, 2025, at 6:24 AM, Christopher Schnick <crschn...@xpipe.io> 
> > <mailto:crschn...@xpipe.io> wrote:
> > 
> > Hello,
> > 
> > I have attached a JVM fatal error log that seemingly was caused by our 
> > JavaFX application entering too many nested event loops, which macOS 
> > apparently doesn't like.
> > 
> > As far as I know, there is no upper limit defined on how often an event 
> > loop can be nested, so I think this is a bug that can occur in rare 
> > situations.
> > 
> > Best
> > Christopher Schnick<hs_err_pid.txt>
> 

Reply via email to