为什么Java 7字节码验证器不会阻塞它?

时间:2013-12-01 15:22:14

标签: java bytecode bytecode-manipulation

我正在研究计算StackFrameMap(SFM)中条目的代码。目标是能够生成(SFM)条目,使Java 7字节码验证器满意。遵循TDD方法,我开始为验证者创建伪造的SMF条目以进行投诉;我会用我正确计算的条目替换它们,看看我是否正确地做了。

问题是:我不能让字节码验证器抱怨。这是一个示例,从原始Java代码开始(此代码不应该做任何有用的事情):

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

    return -x;
}

这将生成以下字节码(使用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 */

现在,我将SFM更改为包含此内容:

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

正如您所看到的,这完全是假的,但是加载时没有错误。我阅读了JVM规范,但我看不出有什么理由可以解决这个问题。我使用SplitBytecodeVerifier选项

编辑:根据下面接受的答案,Eclipse已设置为发出Java 6类文件(版本50.0)。此版本的类文件将悄悄地忽略StackFrameMap的问题。更改设置以使用默认的Java 7类文件格式(51.0)后,它按预期工作。

1 个答案:

答案 0 :(得分:5)

我无法重现您的结果。我尝试修改堆栈帧,但无法按预期加载。如果你愿意,我可以发布我修改过的类文件。

目前尚不清楚发生了什么,但你几乎肯定在某个地方犯了错误。最可能的解释是您的类文件具有版本50.0,在这种情况下,当stackmap无效时,JVM将回退到正常验证。您需要将版本设置为51.0以强制进行堆栈映射验证。另一种可能性是,您只是搞砸了编辑文件,并没有实际保存更改,或者没有进行您认为的更改。

这是我修改过的类文件的程序集。

.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