Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't the Java 7 byteode verifier choke on this?

I'm working on code that calculates entries in the StackFrameMap (SFM). The goal is to be able to generate (SFM) entries that make the Java 7 bytecode verifier happy. Following a TDD methodology, I started by creating bogus SMF entries for the verifier to complain about; I would the replace these with my properly-calculated entries to see that I was doing it correctly.

The problem is: I can't get the bytecode verifier to complain. Here is an example, starting with the original Java code (this code is not supposed to do anything useful):

public int stackFrameTest(int x) {
    if (x > 0) {
        System.out.println("positive x");
    }

    return -x;
}

This generates the following bytecode (with SFM):

  public int stackFrameTest(int);
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: iload_1
         1: ifle          12
         4: getstatic     #47                 // Field java/lang/System.out:Ljava/io/PrintStream;
         7: ldc           #85                 // String positive x
         9: invokevirtual #55                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        12: iload_1
        13: ineg
        14: ireturn
      StackMapTable: number_of_entries = 1
           frame_type = 12 /* same */

Now, I change the SFM to contain this:

  StackMapTable: number_of_entries = 1
       frame_type = 255 /* full_frame */
      offset_delta = 12
      locals = [ double, float ]
      stack = [ double ]

As you can see, that is completely bogus, but it loads without error. I read the JVM spec, and I couldn't see any reason why this would work. I'm not using the SplitBytecodeVerifier option.

EDIT: Per the accepted answer below, Eclipse had been set to emit Java 6 class files (version 50.0). Classfiles of this this version will quietly ignore issues with the StackFrameMap. After changing the setting to use the default Java 7 classfile format (51.0), it worked as expected.

like image 658
Charles Forsythe Avatar asked Dec 01 '13 15:12

Charles Forsythe


1 Answers

I am unable to reproduce your results. I tried modifying the stack frame and it failed to load as expected. If you want, I can post my modified classfile.

It's not clear what happened, but you've almost certainly made a mistake somewhere. The most likely explanation is that your classfile has version 50.0, in which case the JVM will fall back to normal verification when the stackmap is invalid. You need to set the version to 51.0 to force stackmap validation. Another possibility is that you simply messed up editing the file and didn't actually save the changes or didn't make the changes you thought you did.

Here's the assembly for my modified classfile.

.version 51 0
.class super public StackFrameTest4
.super java/lang/Object

.method public <init> : ()V
    .limit stack 1
    .limit locals 1
    aload_0
    invokespecial java/lang/Object <init> ()V
    return
.end method

.method static public main : ([Ljava/lang/String;)V
    .limit stack 2
    .limit locals 1
    new StackFrameTest
    dup
    invokespecial StackFrameTest <init> ()V
    bipush 42
    invokevirtual StackFrameTest stackFrameTest (I)I
    pop
    return
.end method

.method public stackFrameTest : (I)I
    .limit stack 2
    .limit locals 2
    iload_1
    ifle L12
    getstatic java/lang/System out Ljava/io/PrintStream;
    ldc 'positive x'
    invokevirtual java/io/PrintStream println (Ljava/lang/String;)V
L12:
.stack full
    locals Double Float
    stack Double
.end stack

    iload_1
    ineg
    ireturn
.end method
like image 91
Antimony Avatar answered Oct 14 '22 12:10

Antimony