Community
Participate
Working Groups
Simple example to reproduce: package test; public class Main { public static void main(String[] args) throws Throwable { int tmp; try (A a = null) { try (A b = null) { tmp = 0; } } } } class A implements AutoCloseable { @Override public void close() { } } When this code is compiled and run under Eclipse, following exception throwed: Exception in thread "main" java.lang.VerifyError: Stack map does not match the one at exception handler 103 in method test.Main.main([Ljava/lang/String;)V at offset 4 at java.lang.Class.getDeclaredMethods0(Native Method) at java.lang.Class.privateGetDeclaredMethods(Class.java:2442) at java.lang.Class.getMethod0(Class.java:2685) at java.lang.Class.getMethod(Class.java:1620) at sun.launcher.LauncherHelper.getMainMethod(LauncherHelper.java:484) at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:476) When using Oracle Java compiler from JDK 7.0, this code compiles and run without problems. I used component named "Eclipse Java Development Tools Patch for Java 7 Support (BETA) 1.0.0.v20110714-1300" to enable Java 7 support.
I'll take a look.
May be a dup or variant of bug 351653. Very similar to that problem, the verify error goes away if you initialize the variable tmp.
*** Bug 354108 has been marked as a duplicate of this bug. ***
Another test case from bug 354108 import java.io.ByteArrayInputStream; import java.io.InputStream; public class Test { public static void main(String[] args) throws Exception { int b; try (final InputStream in = new ByteArrayInputStream(new byte[] { 42 })) { b = in.read(); } } }
Unless I missed something, this seems to be fixed into the HEAD stream. I'll verify the 3.7 maintenance stream.
It looks like this is also fixed into version v_B74_R37x. Vbs, could you please verify with either one of the latest maintenance build (3.7.x or 4.1.x) or one of the latest I build (3.8 or 4.2).
(In reply to comment #5) > Unless I missed something, this seems to be fixed into the HEAD stream. > I'll verify the 3.7 maintenance stream. Olivier, both Ayush and I could reproduce this in HEAD as well as 3.7.1 maintenance stream top of branch, using JDK 7b147. I have released two disabled regression tests for these via org.eclipse.jdt.core.tests.compiler.regression.TryWithResourcesStatementTest._test055() and org.eclipse.jdt.core.tests.compiler.regression.TryWithResourcesStatementTest._test055a(). Thanks for looking into this.
(In reply to comment #7) > Olivier, both Ayush and I could reproduce this in HEAD as well as > 3.7.1 maintenance stream top of branch, using JDK 7b147. Ok, I got it now. The option -preserveAllLocals needs to be used to reproduce the issue. I'll take a look today.
Ok, I know what is going on. Let's take the example from comment 4. public static void main(String[] args) throws Exception { int b; try (final InputStream in = new ByteArrayInputStream(new byte[] { 42 })) { b = in.read(); } } The uninitialized variable 'b' that is initialized within the twr block has a wrong initialization range. Note that the javac code generation is not perfect as well for the local variable table. It considers only one interval where the variable is actually initialized on multiple intervals. Here is the generated code: public static void main(java.lang.String[] args) throws java.lang.Exception; 0 aconst_null 1 astore_2 2 aconst_null 3 astore_3 4 new java.io.ByteArrayInputStream [19] 7 dup 8 iconst_1 9 newarray byte [8] 11 dup 12 iconst_0 13 bipush 42 15 bastore 16 invokespecial java.io.ByteArrayInputStream(byte[]) [21] 19 astore 4 [in] 21 aload 4 [in] 23 invokevirtual java.io.InputStream.read() : int [24] 26 istore_1 [b] 27 aload 4 [in] 29 ifnull 75 32 aload 4 [in] 34 invokevirtual java.io.InputStream.close() : void [30] 37 goto 75 40 astore_2 41 aload 4 [in] 43 ifnull 51 46 aload 4 [in] 48 invokevirtual java.io.InputStream.close() : void [30] 51 aload_2 52 athrow 53 astore_3 54 aload_2 55 ifnonnull 63 58 aload_3 59 astore_2 60 goto 73 63 aload_2 64 aload_3 65 if_acmpeq 73 68 aload_2 69 aload_3 70 invokevirtual java.lang.Throwable.addSuppressed(java.lang.Throwable) : void [33] 73 aload_2 74 athrow 75 getstatic java.lang.System.out : java.io.PrintStream [39] 78 ldc <String "Done"> [45] 80 invokevirtual java.io.PrintStream.println(java.lang.String) : void [47] 83 return Exception Table: [pc: 21, pc: 27] -> 40 when : java.lang.Throwable [pc: 4, pc: 53] -> 53 when : java.lang.Throwable Line numbers: [pc: 0, line: 7] [pc: 21, line: 8] [pc: 27, line: 9] [pc: 75, line: 10] [pc: 83, line: 11] Local variable table: [pc: 0, pc: 84] local: args index: 0 type: java.lang.String[] [pc: 27, pc: 84] local: b index: 1 type: int [pc: 21, pc: 51] local: in index: 4 type: java.io.InputStream Stack map table: number of frames 6 [pc: 40, full, stack: {java.lang.Throwable}, locals: {java.lang.String[], int, java.lang.Throwable, java.lang.Throwable, java.io.InputStream}] [pc: 51, chop 1 local(s)] [pc: 53, same_locals_1_stack_item, stack: {java.lang.Throwable}] [pc: 63, same] [pc: 73, same] [pc: 75, chop 2 local(s)] You can see thgat the local b is considered to be initialized from 27 till the end of the method. If an exception occurs between line 4 and 27, b is not initialized when reaching the pc 53 (any exception handler), but the stack map in 53 is said to have the same locals from the stack at pc 40 minus the last local (chop at pc 51). This is wrong. The local at position 1 is actually not initialized so we should issue a full stack item instead of the actual stack item. I'll investigate how to fix it. Javac generates the following code: public static void main(String[] args) throws Exception; 0 new ByteArrayInputStream [2] 3 dup 4 iconst_1 5 newarray byte [8] 7 dup 8 iconst_0 9 bipush 42 11 bastore 12 invokespecial ByteArrayInputStream(byte[]) [3] 15 astore_2 [in] 16 aconst_null 17 astore_3 18 aload_2 [in] 19 invokevirtual InputStream.read() : int [4] 22 istore_1 [b] 23 getstatic System.out : PrintStream [5] 26 iload_1 [b] 27 invokevirtual PrintStream.println(int) : void [6] 30 aload_2 [in] 31 ifnull 106 34 aload_3 35 ifnull 56 38 aload_2 [in] 39 invokevirtual InputStream.close() : void [7] 42 goto 106 45 astore 4 [x2] 47 aload_3 48 aload 4 [x2] 50 invokevirtual Throwable.addSuppressed(Throwable) : void [9] 53 goto 106 56 aload_2 [in] 57 invokevirtual InputStream.close() : void [7] 60 goto 106 63 astore 4 65 aload 4 67 astore_3 68 aload 4 70 athrow 71 astore 5 73 aload_2 [in] 74 ifnull 103 77 aload_3 78 ifnull 99 81 aload_2 [in] 82 invokevirtual InputStream.close() : void [7] 85 goto 103 88 astore 6 [x2] 90 aload_3 91 aload 6 [x2] 93 invokevirtual Throwable.addSuppressed(Throwable) : void [9] 96 goto 103 99 aload_2 [in] 100 invokevirtual InputStream.close() : void [7] 103 aload 5 105 athrow 106 getstatic System.out : PrintStream [5] 109 ldc <String "Done"> [10] 111 invokevirtual PrintStream.println(String) : void [11] 114 return Exception Table: [pc: 38, pc: 42] -> 45 when : Throwable [pc: 18, pc: 30] -> 63 when : Throwable [pc: 18, pc: 30] -> 71 when : any [pc: 81, pc: 85] -> 88 when : Throwable [pc: 63, pc: 73] -> 71 when : any Line numbers: [pc: 0, line: 7] [pc: 18, line: 8] [pc: 23, line: 9] [pc: 30, line: 10] [pc: 63, line: 7] [pc: 71, line: 10] [pc: 106, line: 11] [pc: 114, line: 12] Local variable table: [pc: 47, pc: 53] local: x2 index: 4 type: Throwable [pc: 90, pc: 96] local: x2 index: 6 type: Throwable [pc: 16, pc: 106] local: in index: 2 type: InputStream [pc: 0, pc: 115] local: args index: 0 type: String[] [pc: 23, pc: 115] local: b index: 1 type: int Stack map table: number of frames 8 [pc: 45, full, stack: {Throwable}, locals: {String[], int, InputStream, Throwable}] [pc: 56, same] [pc: 63, full, stack: {Throwable}, locals: {String[], _, InputStream, Throwable}] [pc: 71, same_locals_1_stack_item, stack: {Throwable}] [pc: 88, full, stack: {Throwable}, locals: {String[], _, InputStream, Throwable, _, Throwable}] [pc: 99, same] [pc: 103, same] [pc: 106, full, stack: {}, locals: {String[], int}] } You can see the full stack item that is showing an uninitialized variable at position 1. But their local variable entry for 'b' is bogus as well.
Created attachment 201585 [details] Proposed fix + regression tests Srikanth, please verify.
Analysis and fix look good.
Released for both HEAD and 3.7 maintenance streams.
Verified for 3.7 RC2 with build M20110824-0800.
*** Bug 356018 has been marked as a duplicate of this bug. ***
Verified for 3.8M2 using build I20110911-2000.
(In reply to comment #13) > Verified for 3.7 RC2 with build M20110824-0800. This should be 3.7.1 and not 3.7 :)