<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<p>Hey Andy,<br>
<br>
so I think I was able to reproduce this issue for our application.<br>
<br>
There are two main factors how this can happen:<br>
- 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<br>
- As I reported yesterday with
<a class="moz-txt-link-freetext" href="https://mail.openjdk.org/pipermail/openjfx-dev/2025-March/052963.html">https://mail.openjdk.org/pipermail/openjfx-dev/2025-March/052963.html</a>,
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<br>
<br>
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:</p>
<div style="background-color:#1e1f22;color:#bcbec4">
<pre
style="font-family:'JetBrains Mono',monospace;font-size:9,8pt;"><span
style="color:#cf8e6d;">import </span>javafx.application.Application;
<span style="color:#cf8e6d;">import </span>javafx.application.Platform;
<span style="color:#cf8e6d;">import </span>javafx.scene.Scene;
<span style="color:#cf8e6d;">import </span>javafx.scene.control.Alert;
<span style="color:#cf8e6d;">import </span>javafx.scene.control.Button;
<span style="color:#cf8e6d;">import </span>javafx.scene.layout.Region;
<span style="color:#cf8e6d;">import </span>javafx.scene.layout.StackPane;
<span style="color:#cf8e6d;">import </span>javafx.scene.layout.VBox;
<span style="color:#cf8e6d;">import </span>javafx.stage.Stage;
<span style="color:#cf8e6d;">import </span>java.io.IOException;
<span style="color:#cf8e6d;">import </span>java.util.Arrays;
<span style="color:#cf8e6d;">public class </span>ParentBoundsBug <span
style="color:#cf8e6d;">extends </span>Application {
<span style="color:#b3ae60;">@Override
</span><span style="color:#b3ae60;"> </span><span
style="color:#cf8e6d;">public void </span><span
style="color:#56a8f5;">start</span>(Stage stage) <span
style="color:#cf8e6d;">throws </span>IOException {
Thread.<span style="font-style:italic;">setDefaultUncaughtExceptionHandler</span>((thread, throwable) -> {
throwable.printStackTrace();
<span style="color:#cf8e6d;">if </span>(Platform.<span
style="font-style:italic;">isFxApplicationThread</span>()) {
<span style="color:#cf8e6d;">var </span>alert = <span
style="color:#cf8e6d;">new </span>Alert(Alert.AlertType.<span
style="color:#c77dbb;font-style:italic;">ERROR</span>);
alert.setHeaderText(throwable.getMessage());
alert.setContentText(Arrays.<span
style="font-style:italic;">toString</span>(throwable.getStackTrace()));
alert.showAndWait();
} <span style="color:#cf8e6d;">else </span>{
<span style="color:#7a7e85;">// Do some other error handling for non-platform threads
</span><span style="color:#7a7e85;"> // Probably just show the alert with a runLater()
</span><span style="color:#7a7e85;">
</span><span style="color:#7a7e85;"> // For this example, there are no exceptions outside the platform thread
</span><span style="color:#7a7e85;"> </span>}
});
<span style="color:#7a7e85;">// Run delayed as Application::reportException will only be called for exceptions
</span><span style="color:#7a7e85;"> // after the application has started
</span><span style="color:#7a7e85;"> </span>Platform.<span
style="font-style:italic;">runLater</span>(() -> {
Scene scene = <span style="color:#cf8e6d;">new </span>Scene(createContent(), <span
style="color:#2aacb8;">640</span>, <span style="color:#2aacb8;">480</span>);
<span style="color:#c77dbb;">stage</span>.setScene(scene);
<span style="color:#c77dbb;">stage</span>.show();
<span style="color:#c77dbb;">stage</span>.centerOnScreen();
});
}
<span style="color:#cf8e6d;">private </span>Region <span
style="color:#56a8f5;">createContent</span>() {
<span style="color:#cf8e6d;">var </span>b1 = <span
style="color:#cf8e6d;">new </span>Button(<span
style="color:#6aab73;">"Click me!"</span>);
<span style="color:#cf8e6d;">var </span>b2 = <span
style="color:#cf8e6d;">new </span>Button(<span
style="color:#6aab73;">"Click me!"</span>);
<span style="color:#cf8e6d;">var </span>vbox = <span
style="color:#cf8e6d;">new </span>VBox(b1, b2);
b1.boundsInParentProperty().addListener((observable, oldValue, newValue) -> {
<span style="color:#c77dbb;">vbox</span>.setVisible(!<span
style="color:#c77dbb;">vbox</span>.isVisible());
});
b2.boundsInParentProperty().addListener((observable, oldValue, newValue) -> {
<span style="color:#c77dbb;">vbox</span>.setVisible(!<span
style="color:#c77dbb;">vbox</span>.isVisible());
});
vbox.boundsInParentProperty().addListener((observable, oldValue, newValue) -> {
<span style="color:#c77dbb;">vbox</span>.setVisible(!<span
style="color:#c77dbb;">vbox</span>.isVisible());
});
<span style="color:#cf8e6d;">var </span>stack = <span
style="color:#cf8e6d;">new </span>StackPane(vbox, <span
style="color:#cf8e6d;">new </span>StackPane());
stack.boundsInParentProperty().addListener((observable, oldValue, newValue) -> {
<span style="color:#c77dbb;">vbox</span>.setVisible(!<span
style="color:#c77dbb;">vbox</span>.isVisible());
});
<span style="color:#cf8e6d;">return </span>stack;
}
<span style="color:#cf8e6d;">public static void </span><span
style="color:#56a8f5;">main</span>(String[] args) {
<span style="font-style:italic;">launch</span>();
}
}</pre>
</div>
<p><br>
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.</p>
<p>I attached the stacktrace of how this fails. The initial
StackOverflow causes infinitely many following exceptions in the
nested event loop.</p>
<p>Best<br>
Christopher Schnick<br>
</p>
<div class="moz-cite-prefix">On 25/03/2025 18:28, Andy Goryachev
wrote:<br>
</div>
<blockquote type="cite"
cite="mid:DM6PR10MB30179CEC6B7069ADD0AD2101E5A72@DM6PR10MB3017.namprd10.prod.outlook.com">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="Generator"
content="Microsoft Word 15 (filtered medium)">
<style>@font-face
{font-family:"Cambria Math";
panose-1:2 4 5 3 5 4 6 3 2 4;}@font-face
{font-family:"Yu Gothic";
panose-1:2 11 4 0 0 0 0 0 0 0;}@font-face
{font-family:Aptos;
panose-1:2 11 0 4 2 2 2 2 2 4;}@font-face
{font-family:"Iosevka Fixed SS16";
panose-1:2 0 5 9 3 0 0 0 0 4;}@font-face
{font-family:"Times New Roman \(Body CS\)";
panose-1:2 11 6 4 2 2 2 2 2 4;}@font-face
{font-family:"\@Yu Gothic";
panose-1:2 11 4 0 0 0 0 0 0 0;}p.MsoNormal, li.MsoNormal, div.MsoNormal
{margin:0in;
font-size:10.0pt;
font-family:"Aptos",sans-serif;}a:link, span.MsoHyperlink
{mso-style-priority:99;
color:blue;
text-decoration:underline;}span.EmailStyle21
{mso-style-type:personal-reply;
font-family:"Iosevka Fixed SS16";
color:windowtext;}.MsoChpDefault
{mso-style-type:export-only;
font-size:10.0pt;
mso-ligatures:none;}div.WordSection1
{page:WordSection1;}</style>
<div class="WordSection1">
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">Dear
Christopher:<o:p></o:p></span></p>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""><o:p> </o:p></span></p>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">Were
you able to root cause why your application enters that many
nested event loops?<o:p></o:p></span></p>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""><o:p> </o:p></span></p>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">I
believe a well-behaved application should never experience
that, unless there is some design flaw or a bug.<o:p></o:p></span></p>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""><o:p> </o:p></span></p>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">-andy<o:p></o:p></span></p>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""><o:p> </o:p></span></p>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""><o:p> </o:p></span></p>
<div id="mail-editor-reference-message-container">
<div>
<div>
<div
style="border:none;border-top:solid #B5C4DF 1.0pt;padding:3.0pt 0in 0in 0in">
<p class="MsoNormal" style="margin-bottom:12.0pt"><b><span
style="font-size:12.0pt;color:black">From:
</span></b><span
style="font-size:12.0pt;color:black">Christopher
Schnick <a class="moz-txt-link-rfc2396E" href="mailto:crschnick@xpipe.io"><crschnick@xpipe.io></a><br>
<b>Date: </b>Monday, March 10, 2025 at 19:45<br>
<b>To: </b>Andy Goryachev
<a class="moz-txt-link-rfc2396E" href="mailto:andy.goryachev@oracle.com"><andy.goryachev@oracle.com></a><br>
<b>Subject: </b>[External] : Re: JVM crashes on
macOS when entering too many nested event loops<o:p></o:p></span></p>
</div>
<p>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.<br>
<br>
I looked at the documentation, but it seems like the
public API at Platform::enterNestedEventLoop does not
mention this.<br>
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.<br>
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.<br>
<br>
Best<br>
Christopher Schnick<o:p></o:p></p>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">On
10/03/2025 18:51, Andy Goryachev wrote:<o:p></o:p></span></p>
</div>
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
<div>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">This
looks to me like it might be hitting the (native)
thread stack size limit.</span><o:p></o:p></p>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">c.s.glass.ui.Application::enterNestedEventLoop()
even warns about it:</span><o:p></o:p></p>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
<p style="margin:0in;background:white"><span
style="font-family:"Iosevka Fixed SS16";color:#FF2600"> *
An application may enter several nested loops
recursively. There's no</span><o:p></o:p></p>
<p style="margin:0in;background:white"><span
style="font-family:"Iosevka Fixed SS16";color:#FF2600"> *
limit of recursion other than that imposed by the
native stack size.</span><o:p></o:p></p>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">-andy</span><o:p></o:p></p>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
<p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
<div id="mail-editor-reference-message-container">
<div>
<div>
<div
style="border:none;border-top:solid #B5C4DF 1.0pt;padding:3.0pt 0in 0in 0in">
<p class="MsoNormal"
style="margin-bottom:12.0pt"><b><span
style="font-size:12.0pt;color:black">From:
</span></b><span
style="font-size:12.0pt;color:black">openjfx-dev
<a
href="mailto:openjfx-dev-retn@openjdk.org" moz-do-not-send="true">
<openjfx-dev-retn@openjdk.org></a>
on behalf of Martin Fox <a
href="mailto:martinfox656@gmail.com"
moz-do-not-send="true">
<martinfox656@gmail.com></a><br>
<b>Date: </b>Monday, March 10, 2025 at
10:10<br>
<b>To: </b>Christopher Schnick <a
href="mailto:crschnick@xpipe.io"
moz-do-not-send="true"><crschnick@xpipe.io></a><br>
<b>Cc: </b>OpenJFX <a
href="mailto:openjfx-dev@openjdk.org"
moz-do-not-send="true"><openjfx-dev@openjdk.org></a><br>
<b>Subject: </b>Re: JVM crashes on macOS
when entering too many nested event loops</span><o:p></o:p></p>
</div>
<div>
<p class="MsoNormal"
style="margin-bottom:12.0pt"><span
style="font-size:11.0pt">Hi Christopher,<br>
<br>
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.
<br>
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.<br>
<br>
Martin<br>
<br>
> On Mar 7, 2025, at 6:24</span><span
style="font-size:11.0pt;font-family:"Arial",sans-serif"> </span><span
style="font-size:11.0pt">AM, Christopher
Schnick
<a href="mailto:crschnick@xpipe.io"
moz-do-not-send="true"><crschnick@xpipe.io></a>
wrote:<br>
> <br>
> Hello,<br>
> <br>
> 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.<br>
> <br>
> 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.<br>
> <br>
> Best<br>
> Christopher
Schnick<hs_err_pid.txt></span><o:p></o:p></p>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</div>
</div>
</div>
</div>
</blockquote>
</body>
</html>