Bug 469598 - java.lang.VerifyError Expecting a stackmap frame with break and continue in try catch
Summary: java.lang.VerifyError Expecting a stackmap frame with break and continue in t...
Status: NEW
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 4.3.2   Edit
Hardware: PC Windows NT
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: JDT-Core-Inbox CLA
QA Contact:
URL:
Whiteboard: stalebug
Keywords:
Depends on:
Blocks:
 
Reported: 2015-06-08 03:58 EDT by Henno Vermeulen CLA
Modified: 2022-07-01 19:33 EDT (History)
4 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Henno Vermeulen CLA 2015-06-08 03:58:56 EDT
When compiling the following (admittedly sick but valid) Java code within Eclipse and running it (using Oracle Java 1.7.0_60) I get a "java.lang.VerifyError: Expecting a stackmap frame at branch target 11". The code runs fine and prints 10 when first compiling it with javac.

public class BreakContinue {
	public static void main(String[] args) {
		int i;
		for (i = 0; i < 10; i++) {
			try {
				break;
			} finally {
				continue;
			}
		}
		System.out.println(i);
	}
}


Exception in thread "main" java.lang.VerifyError: Expecting a stackmap frame at branch target 11
Exception Details:
  Location:
    Indecisive.decision()Z @11: if_icmplt
  Reason:
    Expected stackmap frame at this location.
  Bytecode:
    0000000: 033b a700 0684 0001 1a10 0aa1 0000 b200
    0000010: 101a b600 2204 ac                      
  Stackmap Table:
    append_frame(@5,Integer)
    same_frame(@8)

	at java.lang.Class.getDeclaredMethods0(Native Method)
	at java.lang.Class.privateGetDeclaredMethods(Class.java:2570)
	at java.lang.Class.getMethod0(Class.java:2813)
	at java.lang.Class.getMethod(Class.java:1663)
	at sun.launcher.LauncherHelper.getMainMethod(LauncherHelper.java:494)
	at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:486)
Comment 1 Henno Vermeulen CLA 2015-06-08 04:01:51 EDT
The stacktrace I posted belonged to an older version of my test program. Here's the correct one:

Exception in thread "main" java.lang.VerifyError: Expecting a stackmap frame at branch target 11
Exception Details:
  Location:
    BreakContinue.main([Ljava/lang/String;)V @11: if_icmplt
  Reason:
    Expected stackmap frame at this location.
  Bytecode:
    0000000: 033c a700 0684 0101 1b10 0aa1 0000 b200
    0000010: 101b b600 16b1                         
  Stackmap Table:
    append_frame(@5,Integer)
    same_frame(@8)

	at java.lang.Class.getDeclaredMethods0(Native Method)
	at java.lang.Class.privateGetDeclaredMethods(Class.java:2570)
	at java.lang.Class.getMethod0(Class.java:2813)
	at java.lang.Class.getMethod(Class.java:1663)
	at sun.launcher.LauncherHelper.getMainMethod(LauncherHelper.java:494)
	at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:486)
Comment 2 Jay Arthanareeswaran CLA 2015-06-08 05:50:54 EDT
Reproduced with the last Mars build. Yet to figure out what went wrong.
Comment 3 Olivier Thomann CLA 2015-06-08 10:22:47 EDT
This is a missing stack map frame. Might be related to wrong optimization in the bytecode. I'll take a look at it today.
Comment 4 Stephan Herrmann CLA 2015-06-08 13:17:48 EDT
Is that legal Java?

While a break is pending we continue its loop (thus leaving the loop body) and then break from the loop from outside its body? Looks scary if you ask me :)
Comment 5 Timo Kinnunen CLA 2015-06-20 07:11:23 EDT
I think so:

14.1. Normal and Abrupt Completion of Statements:
If all the steps are carried out as described, with no indication of abrupt completion, the statement is said to complete normally. However, certain events may prevent a statement from completing normally: 
•The break (§14.15), continue (§14.16), and return (§14.17) statements cause a transfer of control that may prevent normal completion of statements that contain them.

14.20.2. Execution of try-finally and try-catch-finally:
A try statement with a finally block is executed by first executing the try block. Then there is a choice: 
• If execution of the try block completes abruptly for any other reason R, then the finally block is executed, and then there is a choice: 
◦ If the finally block completes abruptly for reason S, then the try statement completes abruptly for reason S (and reason R is discarded). 

So it's like returning from inside a finally block but worse. Wonderful!
Comment 6 Eclipse Genie CLA 2019-12-06 16:22:23 EST
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet.

If you have further information on the current state of the bug, please add it. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.

--
The automated Eclipse Genie.
Comment 7 Stephan Herrmann CLA 2019-12-07 04:39:52 EST
(In reply to Timo Kinnunen from comment #5)
> I think so:
> 
> 14.1. Normal and Abrupt Completion of Statements:
> If all the steps are carried out as described, with no indication of abrupt
> completion, the statement is said to complete normally. However, certain
> events may prevent a statement from completing normally: 
> •The break (§14.15), continue (§14.16), and return (§14.17) statements cause
> a transfer of control that may prevent normal completion of statements that
> contain them.
> 
> 14.20.2. Execution of try-finally and try-catch-finally:
> A try statement with a finally block is executed by first executing the try
> block. Then there is a choice: 
> • If execution of the try block completes abruptly for any other reason R,
> then the finally block is executed, and then there is a choice: 
> ◦ If the finally block completes abruptly for reason S, then the try
> statement completes abruptly for reason S (and reason R is discarded). 

To match this to the example: the reason "break" is discarded when we encounter "continue", right? So "finally { continue; }" is a straight-jacket to the try-block preventing it from terminating the loop by any means? "Interesting" ;p


Using ecj HEAD I see:
$ ecj -1.8 BreakContinue.java
----------
1. WARNING in /tmp/BreakContinue.java (at line 7)
        } finally {
                                continue;
                        }
                  ^^^^^^^^^^^^^^^^^^^^                                                                                                                
finally block does not complete normally                                                                                                              
----------                                                                                                                                            
1 problem (1 warning)                                                                                                                                 
$ java BreakContinue
Error: Unable to initialize main class BreakContinue                                                                                                  
Caused by: java.lang.VerifyError: Instruction type does not match stack map                                                                           
Exception Details:                                                                                                                                    
  Location:                                                                                                                                           
    BreakContinue.main([Ljava/lang/String;)V @11: if_icmplt                                                                                           
  Reason:                                                                                                                                             
    Current frame's stack size doesn't match stackmap.                                                                                                
  Current Frame:                                                                                                                                      
    bci: @11                                                                                                                                          
    flags: { }
    locals: { '[Ljava/lang/String;', integer }
    stack: { integer, integer }
  Stackmap Frame:
    bci: @11
    flags: { }
    locals: { '[Ljava/lang/String;', integer }
    stack: { }
  Bytecode:
    0000000: 033c a700 0684 0101 1b10 0aa1 0000 b200
    0000010: 0d1b b600 13b1                         
  Stackmap Table:
    append_frame(@5,Integer)
    same_frame(@8)
    same_frame(@11)


The byte code looks like this:
  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
         0: iconst_0
         1: istore_1
         2: goto          8
         5: iinc          1, 1
         8: iload_1
         9: bipush        10
        11: if_icmplt     11
        14: getstatic     #13                 // Field java/lang/System.out:Ljava/io/PrintStream;
        17: iload_1
        18: invokevirtual #19                 // Method java/io/PrintStream.println:(I)V
        21: return
      LineNumberTable:
        line 4: 0
        line 4: 5
        line 11: 14
        line 12: 21
      StackMapTable: number_of_entries = 3
        frame_type = 252 /* append */
          offset_delta = 5
          locals = [ int ]
        frame_type = 2 /* same */
        frame_type = 2 /* same */

Looks like the jump target is wrong in
        11: if_icmplt     11

The difference in error messages is probably due to the recent rewrite of stack map generation. The new message can be observed since 4.14M1, but I don't believe it possible to generate a valid stack map for this code sequence.
Comment 8 Stephan Herrmann CLA 2020-02-27 18:49:39 EST
Bulk move to 4.16
Comment 9 Stephan Herrmann CLA 2020-05-18 18:45:28 EDT
Bulk move of unassigned bugs to 4.17
Comment 10 Eclipse Genie CLA 2022-07-01 19:33:07 EDT
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet.

If you have further information on the current state of the bug, please add it. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.

--
The automated Eclipse Genie.