为什么';Java 7字节码验证器不会在这个问题上阻塞吗?

为什么';Java 7字节码验证器不会在这个问题上阻塞吗?,java,bytecode,bytecode-manipulation,Java,Bytecode,Bytecode Manipulation,我正在编写代码来计算StackFrameMap(SFM)中的条目。目标是能够生成使Java7字节码验证器满意的(SFM)条目。遵循TDD方法,我开始创建虚假的SMF条目,供验证者投诉;我会用我正确计算的条目替换这些条目,以确保我做得正确 问题是:我不能让字节码验证器抱怨。下面是一个示例,从原始Java代码开始(该代码不应该做任何有用的事情): 这将生成以下字节码(使用SFM): 现在,我将SFM更改为包含以下内容: StackMapTable: number_of_entries = 1

我正在编写代码来计算StackFrameMap(SFM)中的条目。目标是能够生成使Java7字节码验证器满意的(SFM)条目。遵循TDD方法,我开始创建虚假的SMF条目,供验证者投诉;我会用我正确计算的条目替换这些条目,以确保我做得正确

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

这将生成以下字节码(使用SFM):

现在,我将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)后,它按预期工作。

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

.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
不清楚发生了什么,但你几乎肯定在什么地方犯了错误。最可能的解释是类文件的版本为50.0,在这种情况下,当堆栈映射无效时,JVM将返回到正常验证。您需要将版本设置为51.0以强制stackmap验证。另一种可能是,您只是在编辑文件时出错,没有实际保存更改,或者没有进行您认为已进行的更改

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

.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
.version 51 0
.class超级公共StackFrameTest4
.super java/lang/Object
.public方法:()V
.限制堆栈1
.限制本地人1
阿洛德0
调用特殊的java/lang/Object()V
返回
.结束方法
.method static public main:([Ljava/lang/String;)V
.限制堆栈2
.限制本地人1
新StackFrameTest
重复
调用特殊的StackFrameTest()V
双刺42
invokevirtual StackFrameTest StackFrameTest(I)I
流行音乐
返回
.结束方法
方法:公共堆栈框架测试:(I)I
.限制堆栈2
.限制本地人2
iload_1
ifle L12
获取静态java/lang/System out Ljava/io/PrintStream;
ldc“正x”
invokeVirtualJava/io/PrintStream println(Ljava/lang/String;)V
L12:
.堆满
本地双浮点数
双叠
.端部堆栈
iload_1
伊内格
我返回
.结束方法

你确定类文件版本是51.0吗?另外,你能发布你正在使用的确切类文件吗?我的编译器设置为Java 6,所以我发出类文件50。我知道这将允许“回退”验证,但我没有意识到它允许一个简单的螺旋表。谢谢你的回答。
.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