Bug 567512 - ConcurrentModificationException on clean build with xtext-based builder
Summary: ConcurrentModificationException on clean build with xtext-based builder
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 4.12   Edit
Hardware: PC Linux
: P3 normal (vote)
Target Milestone: 4.18 M3   Edit
Assignee: Simeon Andreev CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2020-10-01 07:12 EDT by Simeon Andreev CLA
Modified: 2020-11-18 02:23 EST (History)
3 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Simeon Andreev CLA 2020-10-01 07:12:06 EDT
We observed this exception in our product.

!ENTRY org.eclipse.core.resources 4 2 2020-08-04 16:06:06.305
!MESSAGE Problems occurred when invoking code from plug-in: "org.eclipse.core.resources".
!STACK 0
java.util.ConcurrentModificationException
	at java.util.HashMap$HashIterator.nextNode(HashMap.java:1442)
	at java.util.HashMap$KeyIterator.next(HashMap.java:1466)
	at org.eclipse.jdt.internal.core.JavaModelManager.secondaryTypesRemoving(JavaModelManager.java:5115)
	at org.eclipse.jdt.internal.core.DeltaProcessor.updateIndex(DeltaProcessor.java:2838)
	at org.eclipse.jdt.internal.core.DeltaProcessor.updateIndex(DeltaProcessor.java:2780)
	at org.eclipse.jdt.internal.core.DeltaProcessor.updateCurrentDeltaAndIndex(DeltaProcessor.java:2596)
	at org.eclipse.jdt.internal.core.DeltaProcessor.traverseDelta(DeltaProcessor.java:2313)
	at org.eclipse.jdt.internal.core.DeltaProcessor.traverseDelta(DeltaProcessor.java:2363)
	at org.eclipse.jdt.internal.core.DeltaProcessor.traverseDelta(DeltaProcessor.java:2363)
	at org.eclipse.jdt.internal.core.DeltaProcessor.traverseDelta(DeltaProcessor.java:2363)
	at org.eclipse.jdt.internal.core.DeltaProcessor.processResourceDelta(DeltaProcessor.java:1964)
	at org.eclipse.jdt.internal.core.DeltaProcessor.resourceChanged(DeltaProcessor.java:2138)
	at org.eclipse.jdt.internal.core.DeltaProcessingState.resourceChanged(DeltaProcessingState.java:477)
	at org.eclipse.core.internal.events.NotificationManager$1.run(NotificationManager.java:305)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:45)
	at org.eclipse.core.internal.events.NotificationManager.notify(NotificationManager.java:295)
	at org.eclipse.core.internal.events.NotificationManager.broadcastChanges(NotificationManager.java:158)
	at org.eclipse.core.internal.resources.Workspace.broadcastPostChange(Workspace.java:379)
	at org.eclipse.core.internal.resources.Workspace.endOperation(Workspace.java:1502)
	at org.eclipse.core.internal.resources.Resource.delete(Resource.java:780)
	at org.eclipse.xtext.builder.BuilderParticipant.cleanOutput(BuilderParticipant.java:495)

I can reproduce a race condition with breakpoints, when adding secondary types and clean building. I see the following concurrent stack traces while debugging:

"Java indexing" #47 daemon prio=4 os_prio=0 tid=0x00007ffff3e95000 nid=0x192ff at breakpoint[0x00007fff8729b000]
   java.lang.Thread.State: RUNNABLE
        at org.eclipse.jdt.internal.core.JavaModelManager.secondaryTypeAdding(JavaModelManager.java:4807)
        at org.eclipse.jdt.internal.core.search.indexing.AbstractIndexer.addTypeDeclaration(AbstractIndexer.java:235)
        at org.eclipse.jdt.internal.core.search.indexing.AbstractIndexer.addClassDeclaration(AbstractIndexer.java:50)
        at org.eclipse.jdt.internal.core.search.indexing.SourceIndexer.indexResolvedDocument(SourceIndexer.java:227)
        at org.eclipse.jdt.internal.core.search.JavaSearchParticipant.indexResolvedDocument(JavaSearchParticipant.java:84)
        at org.eclipse.jdt.internal.core.search.indexing.IndexManager.indexResolvedDocument(IndexManager.java:558)
        at org.eclipse.jdt.internal.core.search.indexing.IndexManager$1.execute(IndexManager.java:1080)
        at org.eclipse.jdt.internal.core.search.processing.JobManager.run(JobManager.java:401)
        at java.lang.Thread.run(Thread.java:748)

"Worker-27: Updating workspace" #509 prio=5 os_prio=0 tid=0x000055555666d800 nid=0x2bd1f at breakpoint[0x00007fff8adc0000]
   java.lang.Thread.State: RUNNABLE
        at org.eclipse.jdt.internal.core.JavaModelManager.secondaryTypesRemoving(JavaModelManager.java:5124)
        at org.eclipse.jdt.internal.core.DeltaProcessor.updateIndex(DeltaProcessor.java:2838)
        at org.eclipse.jdt.internal.core.DeltaProcessor.updateIndex(DeltaProcessor.java:2780)
        at org.eclipse.jdt.internal.core.DeltaProcessor.updateCurrentDeltaAndIndex(DeltaProcessor.java:2596)
        at org.eclipse.jdt.internal.core.DeltaProcessor.traverseDelta(DeltaProcessor.java:2313)
        at org.eclipse.jdt.internal.core.DeltaProcessor.traverseDelta(DeltaProcessor.java:2363)
        at org.eclipse.jdt.internal.core.DeltaProcessor.traverseDelta(DeltaProcessor.java:2363)
        at org.eclipse.jdt.internal.core.DeltaProcessor.processResourceDelta(DeltaProcessor.java:1964)
        at org.eclipse.jdt.internal.core.DeltaProcessor.resourceChanged(DeltaProcessor.java:2138)
        at org.eclipse.jdt.internal.core.DeltaProcessingState.resourceChanged(DeltaProcessingState.java:477)
        at org.eclipse.core.internal.events.NotificationManager$1.run(NotificationManager.java:305)
        at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:45)
        at org.eclipse.core.internal.events.NotificationManager.notify(NotificationManager.java:295)
        at org.eclipse.core.internal.events.NotificationManager.broadcastChanges(NotificationManager.java:158)
        at org.eclipse.core.internal.resources.Workspace.broadcastPostChange(Workspace.java:379)
        at org.eclipse.core.internal.resources.Workspace.endOperation(Workspace.java:1502)
        at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:2308)
        at org.eclipse.core.internal.events.NotificationManager$NotifyJob.run(NotificationManager.java:44)
        at org.eclipse.core.internal.jobs.Worker.run(Worker.java:63)

So far I cannot reproduce this with pure JDT. The clean build in JDT seems to result in calling "JavaModelManager.secondaryTypesRemoving()" only with "cleanIndexCache = false". I'm guessing our xtext-based build does cleaning up differently (it generates Java code, in the exception stack trace above it cleans up what it generated, including secondary types it generated).
Comment 1 Andrey Loskutov CLA 2020-10-01 09:55:16 EDT
Simeon, could you please provide stack based on master / I-build? Should be possible if you use e4x branch. The stack trace seem to be from 4.12 Eclipse.
Comment 2 Simeon Andreev CLA 2020-10-01 11:08:57 EDT
Here is a stack trace from a newer build:

java.util.ConcurrentModificationException
	at java.base/java.util.HashMap$HashIterator.nextNode(HashMap.java:1493)
	at java.base/java.util.HashMap$KeyIterator.next(HashMap.java:1516)
	at org.eclipse.jdt.internal.core.JavaModelManager.secondaryTypesRemoving(JavaModelManager.java:5100)
	at org.eclipse.jdt.internal.core.DeltaProcessor.updateIndex(DeltaProcessor.java:2855)
	at org.eclipse.jdt.internal.core.DeltaProcessor.updateIndex(DeltaProcessor.java:2797)
	at org.eclipse.jdt.internal.core.DeltaProcessor.updateCurrentDeltaAndIndex(DeltaProcessor.java:2613)
	at org.eclipse.jdt.internal.core.DeltaProcessor.traverseDelta(DeltaProcessor.java:2330)
	at org.eclipse.jdt.internal.core.DeltaProcessor.traverseDelta(DeltaProcessor.java:2380)
	at org.eclipse.jdt.internal.core.DeltaProcessor.traverseDelta(DeltaProcessor.java:2380)
	at org.eclipse.jdt.internal.core.DeltaProcessor.processResourceDelta(DeltaProcessor.java:1981)
	at org.eclipse.jdt.internal.core.DeltaProcessor.resourceChanged(DeltaProcessor.java:2155)
	at org.eclipse.jdt.internal.core.DeltaProcessingState.resourceChanged(DeltaProcessingState.java:477)
	at org.eclipse.core.internal.events.NotificationManager$1.run(NotificationManager.java:305)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:45)
	at org.eclipse.core.internal.events.NotificationManager.notify(NotificationManager.java:295)
	at org.eclipse.core.internal.events.NotificationManager.broadcastChanges(NotificationManager.java:158)
	at org.eclipse.core.internal.resources.Workspace.broadcastPostChange(Workspace.java:380)
	at org.eclipse.core.internal.resources.Workspace.endOperation(Workspace.java:1502)
	at org.eclipse.core.internal.resources.InternalWorkspaceJob.run(InternalWorkspaceJob.java:49)
	at org.eclipse.core.internal.jobs.Worker.run(Worker.java:63)
Comment 3 Eclipse Genie CLA 2020-10-02 04:31:57 EDT
New Gerrit change created: https://git.eclipse.org/r/c/jdt/eclipse.jdt.core/+/170198
Comment 4 Simeon Andreev CLA 2020-10-02 05:00:15 EDT
OK, got feedback from Christian on how to reproduce in pure JDT (which didn't occur to me).

1. Set JDT core breakpoints as follows:
   1.1. at line "indexedSecondaryTypes.put((IFile) resource, allTypes);" in JavaModelManager.secondaryTypeAdding(String, char[], char[])
   1.2. at line "IFile cachedFile = cachedFiles.next();" in JavaModelManager.secondaryTypesRemoving(IFile, boolean)
2. Debug Eclipse in a clean workspace.
3. Create a Java project.
4. Create 2 classes "Test1" and "Test2".
5. Add a secondary type in Test1.java:
class Test1Secondary {
}
6. Add a secondary type in Test2.java:
class Test2Secondary {
}
7. Observe breakpoint hit in secondaryTypeAdding(), resume *once*, observe another breakpoint hit (due to the 2nd secondary type).
8. From the Package Explorer, delete Test1.java and Test2.java.
9. Observe a breakpoint hit in secondaryTypesRemoving().
10. Resume the thread suspended at in secondaryTypeAdding().
11. Resume the thread suspended at secondaryTypesRemoving(), observe exception in the log:

!ENTRY org.eclipse.core.resources 4 2 2020-10-02 10:56:30.934
!MESSAGE Problems occurred when invoking code from plug-in: "org.eclipse.core.resources".
!STACK 0
java.util.ConcurrentModificationException
	at java.base/java.util.HashMap$HashIterator.nextNode(HashMap.java:1493)
	at java.base/java.util.HashMap$KeyIterator.next(HashMap.java:1516)
	at org.eclipse.jdt.internal.core.JavaModelManager.secondaryTypesRemoving(JavaModelManager.java:5100)
	at org.eclipse.jdt.internal.core.DeltaProcessor.updateIndex(DeltaProcessor.java:2855)
	at org.eclipse.jdt.internal.core.DeltaProcessor.updateCurrentDeltaAndIndex(DeltaProcessor.java:2613)
	at org.eclipse.jdt.internal.core.DeltaProcessor.traverseDelta(DeltaProcessor.java:2330)
	at org.eclipse.jdt.internal.core.DeltaProcessor.traverseDelta(DeltaProcessor.java:2380)
	at org.eclipse.jdt.internal.core.DeltaProcessor.traverseDelta(DeltaProcessor.java:2380)
	at org.eclipse.jdt.internal.core.DeltaProcessor.traverseDelta(DeltaProcessor.java:2380)
	at org.eclipse.jdt.internal.core.DeltaProcessor.processResourceDelta(DeltaProcessor.java:1981)
	at org.eclipse.jdt.internal.core.DeltaProcessor.resourceChanged(DeltaProcessor.java:2155)
	at org.eclipse.jdt.internal.core.DeltaProcessingState.resourceChanged(DeltaProcessingState.java:477)
	at org.eclipse.core.internal.events.NotificationManager$1.run(NotificationManager.java:305)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:45)
	at org.eclipse.core.internal.events.NotificationManager.notify(NotificationManager.java:295)
	at org.eclipse.core.internal.events.NotificationManager.broadcastChanges(NotificationManager.java:158)
	at org.eclipse.core.internal.resources.Workspace.broadcastPostChange(Workspace.java:380)
	at org.eclipse.core.internal.resources.Workspace.checkpoint(Workspace.java:575)
	at org.eclipse.ltk.core.refactoring.PerformChangeOperation.lambda$0(PerformChangeOperation.java:263)
	at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:2292)
	at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:2317)
	at org.eclipse.ltk.core.refactoring.PerformChangeOperation.executeChange(PerformChangeOperation.java:295)
	at org.eclipse.ltk.internal.ui.refactoring.UIPerformChangeOperation.executeChange(UIPerformChangeOperation.java:94)
	at org.eclipse.ltk.core.refactoring.PerformChangeOperation.run(PerformChangeOperation.java:219)
	at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:2292)
	at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:2317)
	at org.eclipse.ltk.internal.ui.refactoring.WorkbenchRunnableAdapter.run(WorkbenchRunnableAdapter.java:89)
	at org.eclipse.jface.operation.ModalContext$ModalContextThread.run(ModalContext.java:122)
Comment 6 Jay Arthanareeswaran CLA 2020-11-17 22:54:10 EST
Simeon, how are things in your setup? I know you provided the fix. Anyway, if you can confirm things are good, can you mark this one as verified? TIA!
Comment 7 Simeon Andreev CLA 2020-11-18 02:23:24 EST
I've checked with the reproduction steps from comment 4, the problem is fixed (we no longer iterate over the collection during removal; the collection is also now synchronized).