Bug 496178 - ConcurrentModificationException on modifying a List inside a forEach over that List
Summary: ConcurrentModificationException on modifying a List inside a forEach over tha...
Status: UNCONFIRMED
Alias: None
Product: QVTo
Classification: Modeling
Component: Engine (show other bugs)
Version: unspecified   Edit
Hardware: PC Windows 7
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Project Inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-06-15 09:25 EDT by Dennis Hendriks CLA
Modified: 2016-06-16 03:17 EDT (History)
2 users (show)

See Also:


Attachments
Example QVTo transformation to show the issue (187 bytes, text/plain)
2016-06-15 09:28 EDT, Dennis Hendriks CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Dennis Hendriks CLA 2016-06-15 09:25:39 EDT
When modifying a 'List' inside a 'forEach' over that 'List', a java.util.ConcurrentModificationException occurs. QVTo stops executing the remainder of the 'forEach', but does continue with the next statement. In the end, execution of the transformation 'succeeds', and the CME is logged to the Eclipse Error log.

The following is logged:

[log]
Evaluation failed at 'test_cme.qvto:6' with a reason: ConcurrentModificationException. Expression yields an 'invalid' value.

java.util.ConcurrentModificationException
	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:819)
	at java.util.ArrayList$Itr.next(ArrayList.java:791)
	at org.eclipse.m2m.internal.qvt.oml.evaluator.iterators.QvtIterationTemplate.advanceIterators(QvtIterationTemplate.java:159)
	at org.eclipse.m2m.internal.qvt.oml.evaluator.iterators.QvtIterationTemplate.evaluate(QvtIterationTemplate.java:119)
	at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.visitForExp(QvtOperationalEvaluationVisitorImpl.java:1500)
	at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtGenericEvaluationVisitor.visitForExp(QvtGenericEvaluationVisitor.java:446)
	at org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.impl.ForExpImpl.accept(ForExpImpl.java:59)
	at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.visitExpression(QvtOperationalEvaluationVisitorImpl.java:419)
	at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.visitOperationBody(QvtOperationalEvaluationVisitorImpl.java:1169)
	at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.visitEntryOperation(QvtOperationalEvaluationVisitorImpl.java:496)
	at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtGenericEvaluationVisitor.visitEntryOperation(QvtGenericEvaluationVisitor.java:461)
	at org.eclipse.m2m.internal.qvt.oml.expressions.impl.EntryOperationImpl.accept(EntryOperationImpl.java:67)
	at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.executeImperativeOperation(QvtOperationalEvaluationVisitorImpl.java:1968)
	at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.runMainEntry(QvtOperationalEvaluationVisitorImpl.java:2569)
	at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl$1.invoke(QvtOperationalEvaluationVisitorImpl.java:1070)
	at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl$1.invoke(QvtOperationalEvaluationVisitorImpl.java:1)
	at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.doVisitTransformation(QvtOperationalEvaluationVisitorImpl.java:1096)
	at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.visitModule(QvtOperationalEvaluationVisitorImpl.java:878)
	at org.eclipse.m2m.internal.qvt.oml.evaluator.QvtGenericEvaluationVisitor.visitModule(QvtGenericEvaluationVisitor.java:372)
	at org.eclipse.m2m.internal.qvt.oml.expressions.impl.ModuleImpl.accept(ModuleImpl.java:632)
	at org.eclipse.m2m.internal.qvt.oml.runtime.project.QvtInterpretedTransformation.evaluate(QvtInterpretedTransformation.java:185)
	at org.eclipse.m2m.internal.qvt.oml.runtime.project.QvtInterpretedTransformation.run(QvtInterpretedTransformation.java:118)
	at org.eclipse.m2m.internal.qvt.oml.runtime.launch.QvtLaunchConfigurationDelegateBase.doLaunch(QvtLaunchConfigurationDelegateBase.java:194)
	at org.eclipse.m2m.internal.qvt.oml.runtime.launch.QvtLaunchConfigurationDelegateBase.doLaunch(QvtLaunchConfigurationDelegateBase.java:154)
	at org.eclipse.m2m.internal.qvt.oml.runtime.launch.QvtLaunchConfigurationDelegate$1.run(QvtLaunchConfigurationDelegate.java:65)
	at org.eclipse.m2m.internal.qvt.oml.common.launch.SafeRunner$SameThreadRunner.run(SafeRunner.java:33)
	at org.eclipse.m2m.internal.qvt.oml.common.launch.SafeRunner$1.run(SafeRunner.java:26)
	at org.eclipse.m2m.internal.qvt.oml.common.launch.ShallowProcess.run(ShallowProcess.java:45)
	at org.eclipse.m2m.internal.qvt.oml.common.launch.ShallowProcess.run(ShallowProcess.java:36)
	at org.eclipse.m2m.internal.qvt.oml.runtime.launch.QvtLaunchConfigurationDelegate$3.run(QvtLaunchConfigurationDelegate.java:100)
	at java.lang.Thread.run(Thread.java:722)

[/log]
Comment 1 Dennis Hendriks CLA 2016-06-15 09:28:47 EDT
Created attachment 262459 [details]
Example QVTo transformation to show the issue

This is an example QVTo transformation to show the issue. Note that the first iteration of the 'forEach' does result in 'aa' being added to the list. After that, the 'forEach' is not executed further, but the 'log' statement after that is executed. The output is as follows:

[output]
test1, data: [a, b, c]
test2, data: [a, b, c, aa]
[/output]

I think QVTo should either make sure execution does not result in a CME, or fail the entire transformation when the CME occurs. I don't know what the QVT specification says about the semantics here. However, QVTo should definitely not continue execution after such a crash.
Comment 2 Ed Willink CLA 2016-06-15 10:08:19 EDT
(In reply to Dennis Hendriks from comment #1)
> I don't know what the QVT specification says about the semantics here.

8.2.2.6 ForExp: A for expression is an imperative loop expression that iterates over a source collection ... When applying the for expression, if the source collection is not ordered it is implicitly converted into the corresponding ordered collection

This seems to have a clear intent to iterate over an appropriate immutable OCL Collection.

Therefore the Java code must create a copy of the list prior to the iteration, unless it analyses the loop body and all its transitive virtual calls to prove that the list is not modified.

> However, QVTo should definitely not continue execution after such a crash.

Yes. But a different issue.
Comment 3 Dennis Hendriks CLA 2016-06-16 03:17:21 EDT
(In reply to Ed Willink from comment #2)
> > However, QVTo should definitely not continue execution after such a crash.
> 
> Yes. But a different issue.

Will you create a separate bug for that?