Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 366012 - [EditorMgmt] AFE in SaveablesList.decrementRefCount when closing editor
Summary: [EditorMgmt] AFE in SaveablesList.decrementRefCount when closing editor
Status: RESOLVED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 3.8   Edit
Hardware: All All
: P3 major with 3 votes (vote)
Target Milestone: 4.8 M4   Edit
Assignee: Andrey Loskutov CLA
QA Contact:
URL:
Whiteboard:
Keywords:
: 393329 407400 451235 461230 478596 (view as bug list)
Depends on:
Blocks:
 
Reported: 2011-12-08 07:01 EST by Markus Keller CLA
Modified: 2017-11-20 03:18 EST (History)
17 users (show)

See Also:


Attachments
exception stack trace (4.03 KB, text/plain)
2012-10-25 12:12 EDT, Karen Butzke CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Markus Keller CLA 2011-12-08 07:01:23 EST
I20111205-1800

Just found this in the log. I don't know the exact circumstances when this happened, but I think I once had to press Ctrl+W twice to close a compare editor. Could not reproduce.

Error
Thu Dec 08 12:54:36 CET 2011
Unhandled event loop exception

org.eclipse.core.runtime.AssertionFailedException: assertion failed: 
	at org.eclipse.core.runtime.Assert.isTrue(Assert.java:110)
	at org.eclipse.core.runtime.Assert.isTrue(Assert.java:96)
	at org.eclipse.ui.internal.SaveablesList.decrementRefCount(SaveablesList.java:151)
	at org.eclipse.ui.internal.SaveablesList.removeModel(SaveablesList.java:170)
	at org.eclipse.ui.internal.SaveablesList.postClose(SaveablesList.java:658)
	at org.eclipse.ui.internal.WorkbenchPage.closeEditors(WorkbenchPage.java:1449)
	at org.eclipse.ui.internal.WorkbenchPage.closeEditor(WorkbenchPage.java:1527)
	at org.eclipse.ui.internal.CloseEditorHandler.execute(CloseEditorHandler.java:47)
	at org.eclipse.ui.internal.handlers.HandlerProxy.execute(HandlerProxy.java:293)
	at org.eclipse.core.commands.Command.executeWithChecks(Command.java:476)
	at org.eclipse.core.commands.ParameterizedCommand.executeWithChecks(ParameterizedCommand.java:508)
	at org.eclipse.ui.internal.handlers.HandlerService.executeCommand(HandlerService.java:169)
	at org.eclipse.ui.internal.keys.WorkbenchKeyboard.executeCommand(WorkbenchKeyboard.java:468)
	at org.eclipse.ui.internal.keys.WorkbenchKeyboard.press(WorkbenchKeyboard.java:786)
	at org.eclipse.ui.internal.keys.WorkbenchKeyboard.processKeyEvent(WorkbenchKeyboard.java:885)
	at org.eclipse.ui.internal.keys.WorkbenchKeyboard.filterKeySequenceBindings(WorkbenchKeyboard.java:567)
	at org.eclipse.ui.internal.keys.WorkbenchKeyboard.access$3(WorkbenchKeyboard.java:508)
	at org.eclipse.ui.internal.keys.WorkbenchKeyboard$KeyDownFilter.handleEvent(WorkbenchKeyboard.java:123)
	at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:84)
	at org.eclipse.swt.widgets.Display.filterEvent(Display.java:1262)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1052)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1077)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1062)
	at org.eclipse.swt.widgets.Widget.sendKeyEvent(Widget.java:1104)
	at org.eclipse.swt.widgets.Widget.sendKeyEvent(Widget.java:1100)
	at org.eclipse.swt.widgets.Widget.wmChar(Widget.java:1509)
	at org.eclipse.swt.widgets.Control.WM_CHAR(Control.java:4640)
	at org.eclipse.swt.widgets.Canvas.WM_CHAR(Canvas.java:345)
	at org.eclipse.swt.widgets.Control.windowProc(Control.java:4528)
	at org.eclipse.swt.widgets.Canvas.windowProc(Canvas.java:341)
	at org.eclipse.swt.widgets.Display.windowProc(Display.java:4972)
	at org.eclipse.swt.internal.win32.OS.CallWindowProcW(Native Method)
	at org.eclipse.swt.internal.win32.OS.CallWindowProc(OS.java:2439)
	at org.eclipse.swt.internal.BidiUtil.windowProc(BidiUtil.java:639)
	at org.eclipse.swt.internal.win32.OS.DispatchMessageW(Native Method)
	at org.eclipse.swt.internal.win32.OS.DispatchMessage(OS.java:2545)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3752)
	at org.eclipse.ui.internal.Workbench.runEventLoop(Workbench.java:2701)
	at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:2665)
	at org.eclipse.ui.internal.Workbench.access$4(Workbench.java:2499)
	at org.eclipse.ui.internal.Workbench$7.run(Workbench.java:679)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
	at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:668)
	at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149)
	at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:124)
	at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:352)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:624)
	at org.eclipse.equinox.launcher.Main.basicRun(Main.java:579)
	at org.eclipse.equinox.launcher.Main.run(Main.java:1433)
	at org.eclipse.equinox.launcher.Main.main(Main.java:1409)
Comment 1 Remy Suen CLA 2012-03-09 16:26:16 EST
Markus, was wondering why you added the extra if statement? Couldn't you have just used the isTrue(boolean, String) method as is?
http://git.eclipse.org/c/platform/eclipse.platform.ui.git/commit/?id=4305a9e8fbe6c1b6971a4bd1e4e4525885999635
Comment 2 Markus Keller CLA 2012-03-11 13:56:00 EDT
> Markus, was wondering why you added the extra if statement? Couldn't you have
> just used the isTrue(boolean, String) method as is?

The problem with Assert#isTrue(boolean, String) is that the second argument is always evaluated. I didn't want to risk any performance problems or even a ClassCastException if I got something wrong and the key is not a Saveable in certain cases.
Comment 3 Holger Klene CLA 2012-07-11 18:28:17 EDT
Also in my log file ... cannot remember anything special
Version: 4.2.0 Build id: I20120608-1400
Comment 4 Laura C CLA 2012-08-07 13:00:49 EDT
I think I'm getting the same exception or something very similar. It happens when I have one file open in two different compare editors, and if I close the first compare editor before the second. Can reproduce as follows:

1) Compare two files with each other to open a compare editor.
2) Compare one file from step 1 with a third file. Now one file is open in two different compare errors at once.
3) Close the compare editor opened in step 1. 
4) Try to close the compare editor opened in step 2. The editor won't close and an error log entry for the AssertionFailedException appears.

However, no exceptions occur when I close the second compare editor before closing the first.

Reproduced in Eclipse 3.7.2 (build ID 20120216-1857).
Comment 5 Holger Klene CLA 2012-08-26 08:58:14 EDT
Steps of comment 4 also apply to:
Version: 4.3.0M1 Build id: I20120810-1300
Comment 6 Karen Butzke CLA 2012-10-25 12:12:44 EDT
Created attachment 222837 [details]
exception stack trace

I get this with some frequency when doing a 'Close All Editors'. I have no compare editors open. The Close All fails to close any editors, so I repeat the action and it works the second time. I have not found any rhyme or reason for seeing this problem.

I am currently using build 4.2.2-M20121024-1600 with Egit 2.1 installed
Comment 7 Karen Butzke CLA 2012-10-25 12:13:55 EDT
I'm bumping the severity to normal since it is annoying to have the Close All action fail.
Comment 8 Dani Megert CLA 2013-05-08 06:30:49 EDT
*** Bug 407400 has been marked as a duplicate of this bug. ***
Comment 9 Dani Megert CLA 2013-08-23 05:00:01 EDT
*** Bug 393329 has been marked as a duplicate of this bug. ***
Comment 10 Ed Willink CLA 2014-09-22 10:42:11 EDT
I'm seeing this in 4.5M1.

Since the workaround is just to Close All Editors twice, perhaps part of a fix could be to catch the exception more narrowly so that it doesn't cause the close all loop to fail.
Comment 11 Markus Keller CLA 2015-05-29 06:19:05 EDT
*** Bug 461230 has been marked as a duplicate of this bug. ***
Comment 12 Markus Keller CLA 2015-05-29 06:19:39 EDT
*** Bug 451235 has been marked as a duplicate of this bug. ***
Comment 13 Ed Willink CLA 2015-06-27 13:55:35 EDT
Mars. Raising to major since this can occur silently when auto-saving before a launch. Consequently you can waste time debugging stale code.
Comment 14 Markus Keller CLA 2017-06-28 05:37:51 EDT
*** Bug 478596 has been marked as a duplicate of this bug. ***
Comment 15 Dennis Hendriks CLA 2017-09-13 04:51:02 EDT
Also present in:
Version: Oxygen Release (4.7.0)
Build id: 20170620-1800
Comment 16 Andrey Loskutov CLA 2017-10-28 06:09:31 EDT
Still in 4.8. See also Aeri query:
https://dev.eclipse.org/recommenders/committers/aeri/v2/#!/problems/54c4f061bee810030da07fff

Steps to reproduce:

Open history view on some git project.
In any commit, right click one java file and say "compare with working tree".
Compare editor opens.
On the same file in the history view, say "open working tree version".
Java editor opens.
Right click on the editor tab and say "close all".
KABOOM.

Stack trace from 4.8:

org.eclipse.core.runtime.AssertionFailedException: assertion failed: org.eclipse.ui.texteditor.AbstractTextEditor$TextEditorSavable@3943eb67: BasicModule.java
	at org.eclipse.core.runtime.Assert.isTrue(Assert.java:110)
	at org.eclipse.ui.internal.SaveablesList.decrementRefCount(SaveablesList.java:155)
	at org.eclipse.ui.internal.SaveablesList.removeModel(SaveablesList.java:174)
	at org.eclipse.ui.internal.SaveablesList.postClose(SaveablesList.java:702)
	at org.eclipse.ui.internal.WorkbenchPage.firePartClosed(WorkbenchPage.java:5190)
	at org.eclipse.ui.internal.e4.compatibility.CompatibilityPart.lambda$0(CompatibilityPart.java:104)
	at org.eclipse.e4.ui.services.internal.events.UIEventHandler$1.run(UIEventHandler.java:40)
	at org.eclipse.swt.widgets.Synchronizer.syncExec(Synchronizer.java:233)
	at org.eclipse.ui.internal.UISynchronizer.syncExec(UISynchronizer.java:144)
	at org.eclipse.swt.widgets.Display.syncExec(Display.java:4889)
	at org.eclipse.e4.ui.internal.workbench.swt.E4Application$1.syncExec(E4Application.java:212)
	at org.eclipse.e4.ui.services.internal.events.UIEventHandler.handleEvent(UIEventHandler.java:36)
	at org.eclipse.equinox.internal.event.EventHandlerWrapper.handleEvent(EventHandlerWrapper.java:201)
	at org.eclipse.equinox.internal.event.EventHandlerTracker.dispatchEvent(EventHandlerTracker.java:196)
	at org.eclipse.equinox.internal.event.EventHandlerTracker.dispatchEvent(EventHandlerTracker.java:1)
	at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:230)
	at org.eclipse.osgi.framework.eventmgr.ListenerQueue.dispatchEventSynchronous(ListenerQueue.java:148)
	at org.eclipse.equinox.internal.event.EventAdminImpl.dispatchEvent(EventAdminImpl.java:135)
	at org.eclipse.equinox.internal.event.EventAdminImpl.sendEvent(EventAdminImpl.java:78)
	at org.eclipse.equinox.internal.event.EventComponent.sendEvent(EventComponent.java:39)
	at org.eclipse.e4.ui.services.internal.events.EventBroker.send(EventBroker.java:52)
	at org.eclipse.e4.ui.internal.workbench.UIEventPublisher.notifyChanged(UIEventPublisher.java:60)
	at org.eclipse.emf.common.notify.impl.BasicNotifierImpl.eNotify(BasicNotifierImpl.java:374)
	at org.eclipse.e4.ui.model.application.ui.impl.UIElementImpl.setWidget(UIElementImpl.java:261)
	at org.eclipse.e4.ui.workbench.renderers.swt.SWTPartRenderer.unbindWidget(SWTPartRenderer.java:146)
	at org.eclipse.e4.ui.workbench.renderers.swt.SWTPartRenderer.disposeWidget(SWTPartRenderer.java:169)
	at org.eclipse.e4.ui.workbench.renderers.swt.ContributedPartRenderer.disposeWidget(ContributedPartRenderer.java:270)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.safeRemoveGui(PartRenderingEngine.java:935)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.access$1(PartRenderingEngine.java:863)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$4.run(PartRenderingEngine.java:858)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.removeGui(PartRenderingEngine.java:842)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.subscribeTopicToBeRendered(PartRenderingEngine.java:180)
	at sun.reflect.GeneratedMethodAccessor57.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.eclipse.e4.core.internal.di.MethodRequestor.execute(MethodRequestor.java:55)
	at org.eclipse.e4.core.di.internal.extensions.EventObjectSupplier$DIEventHandler.handleEvent(EventObjectSupplier.java:88)
	at org.eclipse.equinox.internal.event.EventHandlerWrapper.handleEvent(EventHandlerWrapper.java:201)
	at org.eclipse.equinox.internal.event.EventHandlerTracker.dispatchEvent(EventHandlerTracker.java:196)
	at org.eclipse.equinox.internal.event.EventHandlerTracker.dispatchEvent(EventHandlerTracker.java:1)
	at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:230)
	at org.eclipse.osgi.framework.eventmgr.ListenerQueue.dispatchEventSynchronous(ListenerQueue.java:148)
	at org.eclipse.equinox.internal.event.EventAdminImpl.dispatchEvent(EventAdminImpl.java:135)
	at org.eclipse.equinox.internal.event.EventAdminImpl.sendEvent(EventAdminImpl.java:78)
	at org.eclipse.equinox.internal.event.EventComponent.sendEvent(EventComponent.java:39)
	at org.eclipse.e4.ui.services.internal.events.EventBroker.send(EventBroker.java:52)
	at org.eclipse.e4.ui.internal.workbench.UIEventPublisher.notifyChanged(UIEventPublisher.java:60)
	at org.eclipse.emf.common.notify.impl.BasicNotifierImpl.eNotify(BasicNotifierImpl.java:374)
	at org.eclipse.e4.ui.model.application.ui.impl.UIElementImpl.setToBeRendered(UIElementImpl.java:303)
	at org.eclipse.e4.ui.internal.workbench.PartServiceImpl.hidePart(PartServiceImpl.java:1354)
	at org.eclipse.e4.ui.internal.workbench.PartServiceImpl.hidePart(PartServiceImpl.java:1284)
	at org.eclipse.e4.ui.workbench.renderers.swt.StackRenderer.closeSiblingParts(StackRenderer.java:1650)
	at org.eclipse.e4.ui.workbench.renderers.swt.StackRenderer.closeSiblingParts(StackRenderer.java:1607)
	at org.eclipse.e4.ui.workbench.renderers.swt.StackRenderer.access$4(StackRenderer.java:1601)
	at org.eclipse.e4.ui.workbench.renderers.swt.StackRenderer$11.widgetSelected(StackRenderer.java:1499)
	at org.eclipse.swt.widgets.TypedListener.handleEvent(TypedListener.java:249)
Comment 17 Andrey Loskutov CLA 2017-10-28 07:41:25 EDT
SaveablesList.incrementRefCount(Map<Saveable, Integer>, Saveable) increments refcount for org.eclipse.egit.ui.internal.revision.GitCompareFileRevisionEditorInput$InternalResourceSaveableComparison even if the org.eclipse.ui.texteditor.AbstractTextEditor$TextEditorSavable is the key, because both implements Saveable.equals() which allows different types to be equal if they represent "same" "shared dirty state".

Now the SaveablesList.modelRefCounts contains InternalResourceSaveableComparison as the key and "2" as value.

This would be OK, but ... the equals() implementation of that keys depends on the state of the objects! Means, once the InternalResourceSaveableComparison is disposed, it is not equal to anything else except itself anymore, and so the attempt to retrieve the refcount for the TextEditorSavable in SaveablesList.decrementRefCount fails.

The point is: SaveablesList implementation depends on the equals() implementation of the Saveables which should NOT be dependent on the object states, but exact the opposite is implemented in LocalResourceSaveableComparison, where the dispose() breaks equals(), as a side effect of fix for bug 353692.
Comment 18 Eclipse Genie CLA 2017-10-30 18:00:33 EDT
New Gerrit change created: https://git.eclipse.org/r/110776
Comment 19 Andrey Loskutov CLA 2017-10-30 18:06:54 EDT
(In reply to Eclipse Genie from comment #18)
> New Gerrit change created: https://git.eclipse.org/r/110776

The idea is to allow "broken" equals() implementations by tracking all "equal" saveables. This patch seem to work but needs tests, therefore "WIP".
Comment 21 Andrey Loskutov CLA 2017-11-20 03:18:28 EST
SaveablesList can work now even if the Saveable.equals() is not properly implemented and changes the behavior during the life cycle of the Saveable.