[jboss-jira] [JBoss JIRA] (JASSIST-195) Verifier error with try-finally clause in Java 1.7

John Brush (JIRA) jira-events at lists.jboss.org
Sat Apr 27 03:50:53 EDT 2013


     [ https://issues.jboss.org/browse/JASSIST-195?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

John Brush updated JASSIST-195:
-------------------------------

    Description: 
After upgrading from Java 1.6 to Java 1.7 our unit tests failed due to the new verifier in 1.7 which requires a stack map. I fixed this issue by adding a call to the rebuildStackMap() method after instrumentation, but this caused a new problem to pop up in one particular instance:

{code}
	public int testInstrumentedCallInFinallyBlock( int i )
	{
		try
		{}
		catch ( Throwable t )
		{}
		finally
		{
			i = incByOne( i );
		}

		return i;
	}
{code} 

This unit test results in the following exception:

java.lang.VerifyError: Stack map does not match the one at exception handler 9 in method xxx.StatementsTestComponent.testInstrumentedCallInFinallyBlock(I)I at offset 9

After some investigation, I noticed that the problem occurred independent of my instrumentation, simply as a result of loading the byte code with Javassist, invoking rebuildStackMap() and then trying to load it. The byte code for the above snippet looks as follows before invoking rebuildStackMap():

{code}
    Code:
      stack=2, locals=3, args_size=2
         0: aload_0       
         1: iload_1       
         2: invokespecial #3                  // Method incByOne:(I)I
         5: istore_1      
         6: goto          18
         9: astore_2      
        10: aload_0       
        11: iload_1       
        12: invokespecial #3                  // Method incByOne:(I)I
        15: istore_1      
        16: aload_2       
        17: athrow        
        18: iload_1       
        19: ireturn       
      Exception table:
         from    to  target type
             9    10     9   any
      StackMapTable: number_of_entries = 2
           frame_type = 73 /* same_locals_1_stack_item */
          stack = [ class java/lang/Throwable ]
           frame_type = 8 /* same */
{code}

Afterwards, it looks like this:

{code}
    Code:
      stack=2, locals=3, args_size=2
         0: aload_0       
         1: iload_1       
         2: invokespecial #23                 // Method incByOne:(I)I
         5: istore_1      
         6: goto          18
         9: nop           
        10: nop           
        11: nop           
        12: nop           
        13: nop           
        14: nop           
        15: goto          9
        18: iload_1       
        19: ireturn       
      Exception table:
         from    to  target type
             9    10     9   any
      StackMapTable: number_of_entries = 2
           frame_type = 249 /* chop */
          offset_delta = 9
           frame_type = 253 /* append */
             offset_delta = 8
        locals = [ class ch/shaktipat/saraswati/instrument/busicomp/StatementsTestComponent, int ]
{code}

Notice the modifications from lines 9-15: this is a result of Javassist's MapMaker.fixDeadcode() method. I assume that the verify error is a result of the exception table entry that refers to code which is no longer there. A possible fix would be to make sure that any exception handlers referring to dead code are removed in such cases. Personally, I would prefer that Javassist simply not modify the code if at all possible, or at least for such modifications to be optional (configurable).

BTW: my only workaround for the time being is to force the 1.7 JVM to use the old verifier with -XX:-UseSplitVerifier.


  was:
After upgrading from Java 1.6 to Java 1.7 our unit tests failed due to the new verifier in 1.7 which requires a stack map. I fixed this issue by adding a call to the rebuildStackMap() method after instrumentation, but this caused a new problem to pop up in one particular instance:

{code}
	public int testInstrumentedCallInFinallyBlock( int i )
	{
		try
		{}
		catch ( Throwable t )
		{}
		finally
		{
			i = incByOne( i );
		}

		return i;
	}
{code} 

This unit test results in the following exception:

java.lang.VerifyError: Stack map does not match the one at exception handler 9 in method xxx.StatementsTestComponent.testInstrumentedCallInFinallyBlock(I)I at offset 9

After some investigation, I noticed that the problem occurred independent of my instrumentation, simply as a result of loading the byte code with Javassist, invoking rebuildStackMap() and then trying to load it. The byte code for the above snippet looks as follows before invoking rebuildStackMap():

{code}
    Code:
      stack=2, locals=3, args_size=2
         0: aload_0       
         1: iload_1       
         2: invokespecial #3                  // Method incByOne:(I)I
         5: istore_1      
         6: goto          18
         9: astore_2      
        10: aload_0       
        11: iload_1       
        12: invokespecial #3                  // Method incByOne:(I)I
        15: istore_1      
        16: aload_2       
        17: athrow        
        18: iload_1       
        19: ireturn       
      Exception table:
         from    to  target type
             9    10     9   any
      StackMapTable: number_of_entries = 2
           frame_type = 73 /* same_locals_1_stack_item */
          stack = [ class java/lang/Throwable ]
           frame_type = 8 /* same */
{code}

Afterwards, it looks like this:

{code}
    Code:
      stack=2, locals=3, args_size=2
         0: aload_0       
         1: iload_1       
         2: invokespecial #23                 // Method incByOne:(I)I
         5: istore_1      
         6: goto          18
         9: nop           
        10: nop           
        11: nop           
        12: nop           
        13: nop           
        14: nop           
        15: goto          9
        18: iload_1       
        19: ireturn       
      Exception table:
         from    to  target type
             9    10     9   any
      StackMapTable: number_of_entries = 2
           frame_type = 249 /* chop */
          offset_delta = 9
           frame_type = 253 /* append */
             offset_delta = 8
        locals = [ class ch/shaktipat/saraswati/instrument/busicomp/StatementsTestComponent, int ]
{code}

Notice the modifications from lines 9-15: this is a result of Javassist's MapMaker.fixDeadcode() method. I assume that the verify error is a result of the exception table entry that refers to code which is no longer there. A possible fix would be to make sure that any exception handlers referring to dead code are removed in such cases. Personally, I would prefer that Javassist simply not modify the code if at all possible, or at least for such modifications to be optional (configurable).




    
> Verifier error  with try-finally clause in Java 1.7
> ---------------------------------------------------
>
>                 Key: JASSIST-195
>                 URL: https://issues.jboss.org/browse/JASSIST-195
>             Project: Javassist
>          Issue Type: Bug
>    Affects Versions: 3.17.1-GA
>         Environment: Oracle Java 1.7 on Mac OS X
>            Reporter: John Brush
>            Assignee: Shigeru Chiba
>
> After upgrading from Java 1.6 to Java 1.7 our unit tests failed due to the new verifier in 1.7 which requires a stack map. I fixed this issue by adding a call to the rebuildStackMap() method after instrumentation, but this caused a new problem to pop up in one particular instance:
> {code}
> 	public int testInstrumentedCallInFinallyBlock( int i )
> 	{
> 		try
> 		{}
> 		catch ( Throwable t )
> 		{}
> 		finally
> 		{
> 			i = incByOne( i );
> 		}
> 		return i;
> 	}
> {code} 
> This unit test results in the following exception:
> java.lang.VerifyError: Stack map does not match the one at exception handler 9 in method xxx.StatementsTestComponent.testInstrumentedCallInFinallyBlock(I)I at offset 9
> After some investigation, I noticed that the problem occurred independent of my instrumentation, simply as a result of loading the byte code with Javassist, invoking rebuildStackMap() and then trying to load it. The byte code for the above snippet looks as follows before invoking rebuildStackMap():
> {code}
>     Code:
>       stack=2, locals=3, args_size=2
>          0: aload_0       
>          1: iload_1       
>          2: invokespecial #3                  // Method incByOne:(I)I
>          5: istore_1      
>          6: goto          18
>          9: astore_2      
>         10: aload_0       
>         11: iload_1       
>         12: invokespecial #3                  // Method incByOne:(I)I
>         15: istore_1      
>         16: aload_2       
>         17: athrow        
>         18: iload_1       
>         19: ireturn       
>       Exception table:
>          from    to  target type
>              9    10     9   any
>       StackMapTable: number_of_entries = 2
>            frame_type = 73 /* same_locals_1_stack_item */
>           stack = [ class java/lang/Throwable ]
>            frame_type = 8 /* same */
> {code}
> Afterwards, it looks like this:
> {code}
>     Code:
>       stack=2, locals=3, args_size=2
>          0: aload_0       
>          1: iload_1       
>          2: invokespecial #23                 // Method incByOne:(I)I
>          5: istore_1      
>          6: goto          18
>          9: nop           
>         10: nop           
>         11: nop           
>         12: nop           
>         13: nop           
>         14: nop           
>         15: goto          9
>         18: iload_1       
>         19: ireturn       
>       Exception table:
>          from    to  target type
>              9    10     9   any
>       StackMapTable: number_of_entries = 2
>            frame_type = 249 /* chop */
>           offset_delta = 9
>            frame_type = 253 /* append */
>              offset_delta = 8
>         locals = [ class ch/shaktipat/saraswati/instrument/busicomp/StatementsTestComponent, int ]
> {code}
> Notice the modifications from lines 9-15: this is a result of Javassist's MapMaker.fixDeadcode() method. I assume that the verify error is a result of the exception table entry that refers to code which is no longer there. A possible fix would be to make sure that any exception handlers referring to dead code are removed in such cases. Personally, I would prefer that Javassist simply not modify the code if at all possible, or at least for such modifications to be optional (configurable).
> BTW: my only workaround for the time being is to force the 1.7 JVM to use the old verifier with -XX:-UseSplitVerifier.

--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira


More information about the jboss-jira mailing list