Bug 558339 - [win32] ConcurrentModificationException in Accessible.lambda$0(Accessible.java:2140)
Summary: [win32] ConcurrentModificationException in Accessible.lambda$0(Accessible.jav...
Status: RESOLVED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: SWT (show other bugs)
Version: 4.14   Edit
Hardware: PC Windows 10
: P3 normal (vote)
Target Milestone: 4.15 M1   Edit
Assignee: Andrey Loskutov CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2019-12-15 14:25 EST by Andrey Loskutov CLA
Modified: 2019-12-20 11:42 EST (History)
4 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Andrey Loskutov CLA 2019-12-15 14:25:13 EST
Found this in my log, have no idea how to reproduce, looks like happened on closing the workbench.

eclipse.buildId=4.15.0.I20191214-1800
java.version=11.0.4
java.vendor=Oracle Corporation
BootLoader constants: OS=win32, ARCH=x86_64, WS=win32, NL=de_DE
Command-line arguments:  -os win32 -ws win32 -arch x86_64

org.eclipse.ui
Error
Sun Dec 15 09:49:51 CET 2019
Unhandled event loop exception

java.util.ConcurrentModificationException
	at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1042)
	at java.base/java.util.ArrayList$Itr.next(ArrayList.java:996)
	at org.eclipse.swt.accessibility.Accessible.lambda$0(Accessible.java:2140)
	at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:89)
	at org.eclipse.swt.widgets.Display.sendEvent(Display.java:4163)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1057)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1081)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1062)
	at org.eclipse.swt.widgets.Widget.release(Widget.java:814)
	at org.eclipse.swt.widgets.ToolBar.releaseChildren(ToolBar.java:821)
	at org.eclipse.swt.widgets.Widget.release(Widget.java:817)
	at org.eclipse.swt.widgets.Composite.releaseChildren(Composite.java:921)
	at org.eclipse.swt.widgets.Canvas.releaseChildren(Canvas.java:174)
	at org.eclipse.swt.widgets.Widget.release(Widget.java:817)
	at org.eclipse.swt.widgets.Widget.dispose(Widget.java:430)
	at org.eclipse.e4.ui.workbench.renderers.swt.SWTPartRenderer.disposeWidget(SWTPartRenderer.java:174)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.safeRemoveGui(PartRenderingEngine.java:945)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.access$1(PartRenderingEngine.java:873)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$4.run(PartRenderingEngine.java:868)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:45)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.removeGui(PartRenderingEngine.java:852)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.safeRemoveGui(PartRenderingEngine.java:900)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.access$1(PartRenderingEngine.java:873)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$4.run(PartRenderingEngine.java:868)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:45)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.removeGui(PartRenderingEngine.java:852)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.safeRemoveGui(PartRenderingEngine.java:925)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.access$1(PartRenderingEngine.java:873)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$4.run(PartRenderingEngine.java:868)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:45)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.removeGui(PartRenderingEngine.java:852)
	at org.eclipse.ui.internal.WorkbenchWindow.hardClose(WorkbenchWindow.java:2161)
	at org.eclipse.ui.internal.WorkbenchWindow.busyClose(WorkbenchWindow.java:1792)
	at org.eclipse.ui.internal.WorkbenchWindow.lambda$3(WorkbenchWindow.java:1817)
	at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:72)
	at org.eclipse.ui.internal.WorkbenchWindow.close(WorkbenchWindow.java:1817)
	at org.eclipse.ui.internal.Workbench$11.run(Workbench.java:1144)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:45)
	at org.eclipse.ui.internal.Workbench.busyClose(Workbench.java:1127)
	at org.eclipse.ui.internal.Workbench.lambda$4(Workbench.java:1428)
	at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:72)
	at org.eclipse.ui.internal.Workbench.close(Workbench.java:1428)
	at org.eclipse.ui.internal.Workbench.close(Workbench.java:1404)
	at org.eclipse.ui.internal.WorkbenchWindow.busyClose(WorkbenchWindow.java:1788)
	at org.eclipse.ui.internal.WorkbenchWindow.lambda$3(WorkbenchWindow.java:1817)
	at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:72)
	at org.eclipse.ui.internal.WorkbenchWindow.close(WorkbenchWindow.java:1817)
	at org.eclipse.ui.internal.WorkbenchWindow.close(WorkbenchWindow.java:1826)
	at org.eclipse.ui.internal.WorkbenchWindow$3.close(WorkbenchWindow.java:529)
	at org.eclipse.e4.ui.workbench.renderers.swt.WBWRenderer.lambda$4(WBWRenderer.java:577)
	at org.eclipse.swt.events.ShellListener$2.shellClosed(ShellListener.java:102)
	at org.eclipse.swt.widgets.TypedListener.handleEvent(TypedListener.java:102)
	at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:89)
	at org.eclipse.swt.widgets.Display.sendEvent(Display.java:4163)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1057)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1081)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1066)
	at org.eclipse.swt.widgets.Decorations.closeWidget(Decorations.java:284)
	at org.eclipse.swt.widgets.Decorations.WM_CLOSE(Decorations.java:1568)
	at org.eclipse.swt.widgets.Control.windowProc(Control.java:4761)
	at org.eclipse.swt.widgets.Canvas.windowProc(Canvas.java:346)
	at org.eclipse.swt.widgets.Decorations.windowProc(Decorations.java:1496)
	at org.eclipse.swt.widgets.Shell.windowProc(Shell.java:2131)
	at org.eclipse.swt.widgets.Display.windowProc(Display.java:4807)
	at org.eclipse.swt.internal.win32.OS.DefWindowProc(Native Method)
	at org.eclipse.swt.widgets.Shell.callWindowProc(Shell.java:508)
	at org.eclipse.swt.widgets.Control.windowProc(Control.java:4860)
	at org.eclipse.swt.widgets.Canvas.windowProc(Canvas.java:346)
	at org.eclipse.swt.widgets.Decorations.windowProc(Decorations.java:1496)
	at org.eclipse.swt.widgets.Shell.windowProc(Shell.java:2131)
	at org.eclipse.swt.widgets.Display.windowProc(Display.java:4807)
	at org.eclipse.swt.internal.win32.OS.DefWindowProc(Native Method)
	at org.eclipse.swt.widgets.Shell.callWindowProc(Shell.java:508)
	at org.eclipse.swt.widgets.Control.windowProc(Control.java:4860)
	at org.eclipse.swt.widgets.Canvas.windowProc(Canvas.java:346)
	at org.eclipse.swt.widgets.Decorations.windowProc(Decorations.java:1496)
	at org.eclipse.swt.widgets.Shell.windowProc(Shell.java:2131)
	at org.eclipse.swt.widgets.Display.windowProc(Display.java:4807)
	at org.eclipse.swt.internal.win32.OS.DispatchMessage(Native Method)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3578)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$5.run(PartRenderingEngine.java:1160)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:338)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:1049)
	at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:155)
	at org.eclipse.ui.internal.Workbench.lambda$3(Workbench.java:660)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:338)
	at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:559)
	at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:154)
	at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:150)
	at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:203)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:137)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:107)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:401)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:255)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:657)
	at org.eclipse.equinox.launcher.Main.basicRun(Main.java:594)
	at org.eclipse.equinox.launcher.Main.run(Main.java:1465)
Comment 1 Eclipse Genie CLA 2019-12-15 14:32:22 EST
New Gerrit change created: https://git.eclipse.org/r/154549
Comment 3 Andrey Loskutov CLA 2019-12-16 04:46:07 EST
Let assume it is fixed now.
Comment 4 Andrey Loskutov CLA 2019-12-16 05:43:05 EST
Just found that this is actually a regression from my favorite "optimization", see commit a205d1112ae9228f8786445e46c1de52bfb1b0a0, and that there was few other similar lines "optimized".

https://git.eclipse.org/r/#/c/153212/5/bundles/org.eclipse.swt/Eclipse+SWT+Accessibility/win32/org/eclipse/swt/accessibility/Accessible.java@919

https://git.eclipse.org/r/#/c/153212/5/bundles/org.eclipse.swt/Eclipse+SWT+Accessibility/win32/org/eclipse/swt/accessibility/Accessible.java@2124

Before the "optimization" we had a memory leak, now ConcurrentModificationException.

One could argue that thanks to optimization we've found a memory leak, but one also could argue that before one tries to optimize code in unknown module, one could try to check what the touched code does.

I will push the fix for the remaining problems above in a moment.
Comment 5 Eclipse Genie CLA 2019-12-16 05:44:03 EST
New Gerrit change created: https://git.eclipse.org/r/154565
Comment 7 Carsten Hammer CLA 2019-12-16 17:50:54 EST
I you ask me the problem is code like this:

public void dispose () {
	if (parent == null) return;
	Release();
	parent.children.remove(this);
	parent = null;
}

It violates the rule that a relationship should have only one owner side and the relationsship should be fully managed from this owner side. Instead it is going from the parent (the code you changed) to the child to the parent to remove the child itself. The "children" datastructure is hold by the parent.

What has the disposal of the child to do with the removal of the parent child relationship? Why is the remove in the dispose() method of the child and not in the internal_dispose_Accessible() method of the parent? 
You could easily use an iterator without creating an additional copy when you iterate on the owner side (parent) over the children. Then you can remove a child and this would even work fully concurrent.
Your fix does not fix the real problem - it rather hides it, imho.
Besides the fact that there obviously is not test for that.
Comment 8 Andrey Loskutov CLA 2019-12-17 00:20:39 EST
(In reply to Carsten Hammer from comment #7)
> I you ask me the problem is code like this:
> 
> public void dispose () {
> 	if (parent == null) return;
> 	Release();
> 	parent.children.remove(this);
> 	parent = null;
> }
> 
> It violates the rule that a relationship should have only one owner side and
> the relationsship should be fully managed from this owner side. Instead it
> is going from the parent (the code you changed) to the child to the parent
> to remove the child itself. The "children" datastructure is hold by the
> parent.
> 
> What has the disposal of the child to do with the removal of the parent
> child relationship? Why is the remove in the dispose() method of the child
> and not in the internal_dispose_Accessible() method of the parent? 
> You could easily use an iterator without creating an additional copy when
> you iterate on the owner side (parent) over the children. Then you can
> remove a child and this would even work fully concurrent.
> Your fix does not fix the real problem - it rather hides it, imho.
> Besides the fact that there obviously is not test for that.

Sure, I agree with you, the code is not nice, but it is there and we have to maintain it.

It looks you have an idea how to make it better - so feel free to refactor and improve related code and add tests. I currently have no time for this, because I constantly spend allmost all my time to fix regressions coming from various optimizations, where authors did not do what you've proposed, but only applied quick fixes...
Comment 9 Andrey Loskutov CLA 2019-12-17 04:31:55 EST
In master now.