Community
Participate
Working Groups
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]
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.
(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.
(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?