JDK-6264013 : Infinite Recursion on EDT causes StackOverflowError
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 5.0u2
  • Priority: P2
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2005-05-02
  • Updated: 2011-01-20
  • Resolved: 2006-08-18
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other JDK 6
5.0u10Fixed 6 b96Fixed
Related Reports
Relates :  
Description
When running the Yokogawa applet-based application an infinite recursion happens on the EDT with j2se 5.0 u2.

The silk-automated test opens and closes windows repeatedly for about 1 day. Each window is a new applet. After running for 1 day, an attempt to close an applet window causes java.lang.StackOverflowError caused by awt infinite recursion as indicated below. A popup comes up and says "Java General Exception", the stack trace is as follows:

Exception in thread "AWT-EventQueue-10640" java.lang.StackOverflowError
at java.awt.AWTEventMulticaster.removeInternal(AWTEventMulticaster.java:837)
at java.awt.Toolkit$ToolkitEventMulticaster.remove(Toolkit.java:2090)
at java.awt.AWTEventMulticaster.removeInternal(AWTEventMulticaster.java:837)
at java.awt.Toolkit$ToolkitEventMulticaster.remove(Toolkit.java:2090)
at java.awt.AWTEventMulticaster.removeInternal(AWTEventMulticaster.java:837)
at java.awt.Toolkit$ToolkitEventMulticaster.remove(Toolkit.java:2090)
at java.awt.AWTEventMulticaster.removeInternal(AWTEventMulticaster.java:837)
at java.awt.Toolkit$ToolkitEventMulticaster.remove(Toolkit.java:2090)
at java.awt.AWTEventMulticaster.removeInternal(AWTEventMulticaster.java:837)
at java.awt.Toolkit$ToolkitEventMulticaster.remove(Toolkit.java:2090)
at java.awt.AWTEventMulticaster.removeInternal(AWTEventMulticaster.java:837)
at java.awt.Toolkit$ToolkitEventMulticaster.remove(Toolkit.java:2090)
at java.awt.AWTEventMulticaster.removeInternal(AWTEventMulticaster.java:837)
at java.awt.Toolkit$ToolkitEventMulticaster.remove(Toolkit.java:2090)
at java.awt.AWTEventMulticaster.removeInternal(AWTEventMulticaster.java:837)
at java.awt.Toolkit$ToolkitEventMulticaster.remove(Toolkit.java:2090)
at java.awt.AWTEventMulticaster.removeInternal(AWTEventMulticaster.java:837)
at java.awt.Toolkit$ToolkitEventMulticaster.remove(Toolkit.java:2090)
at java.awt.AWTEventMulticaster.removeInternal(AWTEventMulticaster.java:837)
at java.awt.Toolkit$ToolkitEventMulticaster.remove(Toolkit.java:2090)
at java.awt.AWTEventMulticaster.removeInternal(AWTEventMulticaster.java:837)
at java.awt.Toolkit$ToolkitEventMulticaster.remove(Toolkit.java:2090)
at java.awt.AWTEventMulticaster.removeInternal(AWTEventMulticaster.java:837)
at java.awt.Toolkit$ToolkitEventMulticaster.remove(Toolkit.java:2090)
at java.awt.AWTEventMulticaster.removeInternal(AWTEventMulticaster.java:837)
at java.awt.Toolkit$ToolkitEventMulticaster.remove(Toolkit.java:2090)
at java.awt.AWTEventMulticaster.removeInternal(AWTEventMulticaster.java:837)
at java.awt.Toolkit$ToolkitEventMulticaster.remove(Toolkit.java:2090)
at java.awt.AWTEventMulticaster.removeInternal(AWTEventMulticaster.java:837)
at java.awt.Toolkit$ToolkitEventMulticaster.remove(Toolkit.java:2090)
at java.awt.AWTEventMulticaster.removeInternal(AWTEventMulticaster.java:837)
at java.awt.Toolkit$ToolkitEventMulticaster.remove(Toolkit.java:2090)
at java.awt.AWTEventMulticaster.removeInternal(AWTEventMulticaster.java:837)
at java.awt.Toolkit$ToolkitEventMulticaster.remove(Toolkit.java:2090)
.............................(same frames repeated many more times)

The java console log is attached to this bug report. Thread dump is attached as well.

The application is still running in Sun's Santa Clara QA lab. Please contact submitter if help with diagnosing this issue is needed.
###@###.### 2005-05-02 00:03:25 GMT

Comments
WORK AROUND While looking at the AppContext.dispose() code, I thought of a possible workaround. During the course of the dispose() method, all of the AppContext's ownerless windows are also dispose()d. By overriding Frame.dispose() to call LookAndFeel.uninitialize() and creating a realized but unshown Frame, we can avoid leaking AWTEventListeners. ... class WorkaroundWindow extends Frame { public WorkaroundWindow() { super(); pack(); } public void dispose() { super.dispose(); SwingUtilities.invokeLater(new Runnable() { public void run() { LookAndFeel laf = UIManager.getLookAndFeel(); if (laf != null) { laf.uninitialize(); } } }); } } public void start() { WorkaroundWindow ww = new WorkaroundWindow(); } ... Putting the laf.uninitialize() call in an invokeLater() ensures it happens after all top-levels have been disposed by the AppContext. Obviously this is a bit of a kludge, but it does work (at least with my test case). Be very careful not to prematurely dispose() the workaround window, as it will mess up the LookAndFeel for the rest of your GUI!
04-08-2006

EVALUATION To fix this bug, we need to alert BasicLookAndFeel when its AppContext is being disposed so that the LAf can uninitialize() itself.
04-08-2006

EVALUATION I figured out a way to reproduce this with a standalone test case (attached). The test is basically just a JButton (w/ a popup) that dumps the list of AWTEventListeners when clicked. I put the applet into a signed .jar. To reproduce the bug: 1) open a new tab in your browser 2) run the applet, and click the button to see the list of AWTEventListeners dumped to the Java console 3) close the tab (you need to have another browser tab/window open so the browser will stay open) 4) goto 1 Each time through the loop, an additional BasicLookAndFeel$PopupInvocationHelper is added to the list. The current theory is that when applet quits, its AppContext disappears before Swing has a chance to remove the listener. (Note that running multiple copies of the applet at the same time does NOT cause additional listeners to be added - presumably they all run in the same AppContext).
14-07-2006

EVALUATION I put a dump of all listeners in Toolkit.addAWTEventListener and found that all remained items are javax.swing.plaf.basic.BasicLookAndFeel$PopupInvocationHelper. (Since JDK6.0 it calls javax.swing.plaf.basic.BasicLookAndFeel$AWTEventHelper but I can't even try to reproduce it with Mustang) Looking on BasicLookAndFeel I noticed that BasicPopupMenuUI is not clearing listener. It's reasonable to make an explicit removal in uninstallListeners() but it doesn't have any effect - the bug is still reproducible. A pair of standalone tests doesn't recreate the defect.
11-07-2006

EVALUATION Previous statement about undisposed EmbeddedFrame is not quite true. That time I thought it's a problem with plugin that doesn't dispose embedded frame object on WindowClosing. At least I'm not able to emulate the case in my environment without Yokogava application(I'm using simple applet). All listeners are being removed properly and every embedded frame is being disposed on time.
04-07-2006

EVALUATION In a standalone application we may dispose EmbeddedFrame by ourself and it solves the problem - peer is disposed and container is removeNotifi'ed. This like a correct application should behave. But ordinary applet can't access EmbeddedFrame and it should happen on Frame.dispose(). AWT does nothing to free embedded frame in that case because frame doesn't take into account its embbeded frame if any. Fortunately it works fine on Linux because that MouseExited event initiates lightweightDispatcher disposal. But I'm not sure that EmbeddedFrame is also eliminates. So it would be great to dispose embedded frame explicitly and not rely on ExitedEvent.
03-07-2006

EVALUATION The defect symptoms comes to an awt issue. A component in a frame is receiving MouseExited on frame's dispose() on X11. But it doesn't on Win32. As the AWTEventListener lightweightDispatcher would only be disposed when MouseExited comes then it stays the same on Win32. That this is a native behavior and we should try to workaround it. Suppose we may track dispose and clear lightweightDispatcher explicitly by ourselves without that missed mouse event.
03-07-2006

EVALUATION Applet creation supposes addition of an Applet into EmbeddedFrame. Standalone test emulates this. Though just Frame.add(new Applet()) doesn't shows the problem. Each instance (a frame and an applet) initilizes it's own Container.LightweightDispatcher class. It implements AWTEventListener so is ready to be integrated into Toolkit with addAWTEventListener(). But removing of that listener happens from the different toplevel instances i.e. one of LightweightDispatchers constructed and pushed as a listener into Toolkit on applet constuction. In turn on disposing of that frame another LightweightDispatcher is attempted to be eliminated from Toolkit by that frame. Here is the contradiction: Toolkit is using a HashMap to store all listeners in. Once it receives a request to erase non-existing listener another one is still there. The problem only reproducible with lightweight component in that applet. I noticed that mouse should be positioned over the applet to get this defect to appear.
29-06-2006

EVALUATION I could reproduce the problem locally with an EmbeddedFrame owning JApplet(Applet - doesn't matter). The test shows the increasing number of AWTEventListeners in toolkit whereas we invoke add/remove correctly. Suppose it's a defect in Toolkit implementation. The bug reproducible with JDk6.0 as well as JDK1.5.0.
27-06-2006

EVALUATION I verified a hierarchy of components as they created in browser: a Frame includes an embedded Frame which in turn includes Applet. To get a leak (believe we just don't erase AWTListener somewhere in) I repeatedly creating and closing these Frames but the number of listeners doens't grow. Seem this approach is not exactly the same as in original application.
26-06-2006

EVALUATION After a further investigation it's likely the problem is in JDK; more precisely in Container.lightweightDispatcher class. Initially we thought that application itself doesn't handle listeners correctly. Now I see that listeners are added/remove on mouseEntered/Exited events. This is reasonable and expected behavior but we probably may not handle them right on non-standard situations like window closing, ALT-TAB etc. We should inversitgate it better. Belive I would be able to write a test demonstrating the issue without applet and that test suite.
13-06-2006

EVALUATION Seems this occur because of recursive algorithm inside AWTEventMulticaster: we call to ToolkitEventMulticaster.remove(l) then to AWTEventMulticaster.removeInternal(l, l1) and then we get loop like: AWTEventMulticaster.remove -> AWTEventMulticaster.removeInternal() -> AWTEventMulticaster.remove() ->... and so on. The bug might be reproduced with a small test in Comments section. All we need is to put a large number of AWTEventListeners (I use 6000) into Toolkit and then remove one of them. Each remove will cause StackOverflowException. I wonder if possible to modify Yokogawa applet and verify that listeners correctly removes after they are not needed anymore. ###@###.### 2005-05-11 14:01:51 GMT
11-05-2005