Community
Participate
Working Groups
I get "java.lang.ClassFormatError: Code segment has wrong length in class file" when I compile/execute the following class ================================= package test.cheetah; import java.util.ArrayList; public class CodeSegmentTest { public static void main(String[] args) { ArrayList<Object> l; switch (args.length) { case 1: l = new ArrayList<Object>(); break; default: return; } } } ================================= The same code works fine when compiled/executed by javac/java. Win2k SP4, Eclipse 200406192000, cheetah as of June 21st, 10:30pm EDT ;-), Sun JDK 1.5.0 beta2. I use Sun JDK 1.4.2_04 to run eclipse itself.
Could not reproduce with latest code in the 1.5 branch and the 1.5 b56. Closing as WORKSFORME. Please reopen if you get it again with a new cheetah drop.
This is still a problem with latest org.eclipse.jdt.core branch JDK_1_5. I have verified this on two systems with SUN 1.5 beta2 and b57. Note that on both systems I have two eclipse workspaces. I checkout JDK_1_5 org.eclipse.jdt.core into one workspace and start second workspace using "Run-time workbench" launch configuration. I do all 1.5 development in the second workspace. The only compiler option that I changed is compiler compliance level. I can provide you terminal services access to one of the machines if you want, my ibm email is igorf at ca ibm com.
Created attachment 12874 [details] classfile that has this problem
I will continue to investigate.
The bug occurs if I have -perserveAllLocals on the command line. If I don't, it works fine.
PreserveAllLocals isn't the offending, Problem is rather in debug attributes for local variables: '-g:vars'. Offending entries are: Local variable table: ... [pc: 28, pc: 38] local: l index: 1 type: .../ArrayList; [pc: 47, pc: 48] local: l index: 1 type: .../ArrayList; Local variable type table: [pc: 28, pc: 38] local: l index: 1 type: .../ArrayList<Ljava/lang/Object;>; [pc: 47, pc: 48] local: l index: 1 type: .../ArrayList<Ljava/lang/Object;>; where javac does generate: Local variable table: ... [pc: 28, pc: 48] local: l index: 1 type: .../ArrayList; Local variable type table: [pc: 28, pc: 48] local: l index: 1 type: .../ArrayList<Ljava/lang/Object;>;
Based on our bytecode sequence, I believe our attribute are valid, and seem to be rejected by the VM. The 'return' statement in default case is triggering this behavior, as we correctly infer that the second 'return' statement can only be reached through a path where the variable is definitely assigned. javac doesn't notice that in default case the variable loses its assignment state, and would thus incorrectly display it in debugger. I suspect the one bytecode line number interval is not properly handled at VM level. // Method descriptor #15 ([Ljava/lang/String;)V // Stack: 2, Locals: 2 public static void main(String[] args); 0 aload_0 1 arraylength 2 tableswitch default: 38 case 1: 20 20 new #17 java/util/ArrayList 23 dup 24 invokespecial #18 <Method java/util/ArrayList.<init>()V> 27 astore_1 28 getstatic #24 <Field java/lang/System.out Ljava/io/PrintStream;> 31 aload_1 32 invokevirtual #30 <Method java/io/PrintStream.println(Ljava/lang/Object;) 35 goto 47 38 getstatic #24 <Field java/lang/System.out Ljava/io/PrintStream;> 41 ldc #32 <String "SUCCESS"> 43 invokevirtual #35 <Method java/io/PrintStream.println(Ljava/lang/String;) 46 return 47 return
Indeed, if adding a read access to variable 'l' in default case, javac correctly reports an error (variable may not have been initialized), thus it should not include this interval in the local variable attribute.
Interestingly enough, the issue only occurs if using generics. Problem is thus located in VM reading of local variable type table (the new attribute for encoding generic type info about local variables).
Actually, we shouldn't have more than one entry per local variable. It looks like it should span over the unitialized ranges?
I take back my previous comment. Actually, on following code, javac generates 2 entries. Local variable table: [pc: 6, pc: 9] local: i index: 1 type: ...ArrayList; [pc: 0, pc: 18] local: args index: 0 type: [...String; [pc: 10, pc: 18] local: i index: 1 type: ..ArrayList; Local variable type table: [pc: 6, pc: 9] local: i index: 1 type: ...ArrayList<Ljava/lang/Object;>; [pc: 10, pc: 18] local: i index: 1 type: ...ArrayList<Ljava/lang/Object;>; public class X { public static void main(String[] args) { java.util.ArrayList<Object> i; outer: { if (args == null) { i = null; break outer; } return; } System.out.println(i); } }
When replacing last println statement with return, to cause last interval to be of size 1, it still works: Local variable table: [pc: 6, pc: 9] local: i index: 1 type: Ljava/util/ArrayList; [pc: 0, pc: 11] local: args index: 0 type: [Ljava/lang/String; [pc: 10, pc: 11] local: i index: 1 type: Ljava/util/ArrayList; Local variable type table: [pc: 6, pc: 9] local: i index: 1 type: ...ArrayList<Ljava/lang/Object;>; [pc: 10, pc: 11] local: i index: 1 type: ...ArrayList<Ljava/lang/Object;>;
Fixed and released in HEAD. Regression tests added.