Infinite loop fix breaks JavaFlow continuation support
The commit below broke support for the (now rather obsolete) commons-javaflow project, or rather it
breaks the unit tests with class loading issues.
commit 2b155e17098a41a38d3819d79a7c6ec69d7a1e07
Author: ebruneton <ebruneton@271bd773-ee82-43a6-9b2b-1890ed8ce7f9>
Date: Sat Sep 1 15:52:49 2012 +0000
Fixed bug in MethodNode (infinite loops when trying to copy a MethodNode into another several
times).
Added unit test for this case (failing without the bug fix).
diff --git a/asm/src/org/objectweb/asm/tree/MethodNode.java
b/asm/src/org/objectweb/asm/tree/MethodNode.java
index f3bbdbd..bf380cf 100644
--- a/asm/src/org/objectweb/asm/tree/MethodNode.java
+++ b/asm/src/org/objectweb/asm/tree/MethodNode.java
@@ -458,7 +458,7 @@ public class MethodNode extends MethodVisitor {
*/
protected LabelNode getLabelNode(final Label l) {
if (!(l.info instanceof LabelNode)) {
- l.info = new LabelNode(l);
+ l.info = new LabelNode();
}
return (LabelNode) l.info;
}
diff --git a/asm/test/conform/org/objectweb/asm/tree/ClassNodeUnitTest.java
b/asm/test/conform/org/objectweb/asm/tree/ClassNodeUnitTest.java
index 5754b81..988038b 100644
--- a/asm/test/conform/org/objectweb/asm/tree/ClassNodeUnitTest.java
+++ b/asm/test/conform/org/objectweb/asm/tree/ClassNodeUnitTest.java
@@ -32,6 +32,7 @@ package org.objectweb.asm.tree;
import junit.framework.TestCase;
import org.objectweb.asm.Handle;
+import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
/**
@@ -138,4 +139,18 @@ public class ClassNodeUnitTest extends TestCase implements Opcodes {
MultiANewArrayInsnNode manan = new MultiANewArrayInsnNode("[[I", 2);
assertEquals(AbstractInsnNode.MULTIANEWARRAY_INSN, manan.getType());
}
+
+ public void testCloneMethod() {
+ MethodNode n = new MethodNode();
+ Label l0 = new Label();
+ Label l1 = new Label();
+ n.visitCode();
+ n.visitLabel(l0);
+ n.visitInsn(Opcodes.NOP);
+ n.visitLabel(l1);
+ n.visitEnd();
+ MethodNode n1 = new MethodNode();
+ n.accept(n1);
+ n.accept(n1);
+ }
}
The class loading issue that arises is the following stack trace:
java.lang.NoClassDefFoundError: org/apache/commons/javaflow/rewrite/Simple
at
org.apache.commons.javaflow.suite.VerificationTestCase.testSimpleSuspend(VerificationTestCase.java:18
8)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at junit.framework.TestCase.runTest(TestCase.java:176)
at junit.framework.TestCase.runBare(TestCase.java:141)
at junit.framework.TestResult$1.protect(TestResult.java:122)
at junit.framework.TestResult.runProtected(TestResult.java:142)
at junit.framework.TestResult.run(TestResult.java:125)
at junit.framework.TestCase.run(TestCase.java:129)
at junit.framework.TestSuite.runTest(TestSuite.java:252)
at junit.framework.TestSuite.run(TestSuite.java:247)
at junit.framework.TestSuite.runTest(TestSuite.java:252)
at junit.framework.TestSuite.run(TestSuite.java:247)
at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:86)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: java.lang.ClassNotFoundException: org.apache.commons.javaflow.rewrite.Simple Undefined
label used
at
org.apache.commons.javaflow.helper.ClassTransformerClassLoader.loadClass(ClassTransformerClassLoa
der.java:113)
... 22 more
Caused by: java.lang.IllegalStateException: Undefined label used
at org.objectweb.asm.util.CheckMethodAdapter.visitMaxs(CheckMethodAdapter.java:1013)
at
org.apache.commons.javaflow.bytecode.transformation.asm.ContinuationMethodAdapter.visitMaxs(Conti
nuationMethodAdapter.java:313)
at org.objectweb.asm.tree.MethodNode.accept(MethodNode.java:835)
at
org.apache.commons.javaflow.bytecode.transformation.asm.ContinuationMethodAnalyzer.visitEnd(Contin
uationMethodAnalyzer.java:140)
at org.objectweb.asm.ClassReader.readMethod(ClassReader.java:1036)
at org.objectweb.asm.ClassReader.accept(ClassReader.java:708)
at org.objectweb.asm.ClassReader.accept(ClassReader.java:521)
at
org.apache.commons.javaflow.bytecode.transformation.asm.AsmClassTransformer.transform(AsmClassTr
ansformer.java:49)
at
org.apache.commons.javaflow.bytecode.transformation.asm.AsmClassTransformer.transform(AsmClassTr
ansformer.java:41)
at
org.apache.commons.javaflow.helper.ClassTransformerClassLoader.transform(ClassTransformerClassLoa
der.java:58)
at
org.apache.commons.javaflow.helper.ClassTransformerClassLoader.loadClass(ClassTransformerClassLoa
der.java:102)
... 22 more
Which is caused by the CheckMethodAdapter.visitMax(...) done in the following code:
public void visitMaxs(int maxStack, int maxLocals) {
Label endLabel = new Label();
mv.visitLabel(endLabel);
mv.visitLocalVariable("__stackRecorder", "L" + STACK_RECORDER + ";", null, startLabel, endLabel,
stackRecorderVar);
mv.visitMaxs(0, 0);
}
Reïntroducing the l parameter to the LabelNode constructor fixes these exceptions.
I have no experience in both ASM and javaflow frameworks, but try to ensure that javaflow and a recent
release of ASM work together.
You can find the code for the javaflow project here (if necessary):
https://github.com/topicusonderwijs/commons-javaflow
The method that falls flat with the exception is the following:
https://github.com/topicusonderwijs/commons-
javaflow/blob/master/src/main/java/org/apache/commons/javaflow/bytecode/transformation/asm/Continu
ationMethodAdapter.java#L313