0

我正在尝试通过在特定指令之前插入调用来修改方法。似乎我的检测会导致不同的堆栈映射表,该表不能由 bcel 包本身自动生成。因此,我的检测类文件包含旧的堆栈映射表,这会导致 jvm 出错。我已经尝试过使用 MethodGen 的方法 removeCodeAttributes,它可以删除所有代码属性。它可以在简单的情况下工作,例如包装函数。它现在不能在我的情况下工作。

public class Insert{
    public static void main(String[] args) throws ClassFormatException, IOException{
        Insert isrt = new Insert();
        String className = "StringBuilder.class";
        JavaClass jclzz = new ClassParser(className).parse();
        ClassGen cgen = new ClassGen(jclzz);
        ConstantPoolGen cpgen = cgen.getConstantPool();
        MethodGen mgen = new MethodGen(jclzz.getMethods()[1], className, cpgen);
        InstructionFactory ifac = new InstructionFactory(cgen);
        InstructionList ilist = mgen.getInstructionList();
        for (InstructionHandle ihandle : ilist.getInstructionHandles()){
            System.out.println(ihandle.toString());
        }
        InstructionFinder f = new InstructionFinder(ilist);
        InstructionHandle[] insert_pos = (InstructionHandle[])(f.search("invokevirtual").next());
        Instruction inserted_inst = ifac.createInvoke("java.lang.System", "currentTimeMillis", Type.LONG, Type.NO_ARGS, Constants.INVOKESTATIC);
        System.out.println(inserted_inst.toString());
        ilist.insert(insert_pos[0], inserted_inst);


        mgen.setMaxStack();
        mgen.setMaxLocals();


        mgen.removeCodeAttributes();
        cgen.replaceMethod(jclzz.getMethods()[1], mgen.getMethod());

        ilist.dispose();
        //output the file
        FileOutputStream fos = new FileOutputStream(className);
        cgen.getJavaClass().dump(fos);
        fos.close();
    }
}
4

1 回答 1

2

删除 aStackMapTable不是修复错误的正确解决方案StackMapTable。重要的引用是:

4.7.4. StackMapTable 属性

class版本号为 50.0 或更高版本的文件中,如果方法的Code属性没有StackMapTable属性,则它具有隐式堆栈映射属性第 4.10.1 节)。此隐式堆栈映射属性等效于等于零的StackMapTable属性。number_of_entries

由于StackMapTable每个分支目标都必须具有显式条目,因此这种隐式StackMapTable仅适用于无分支方法。但是在这些情况下,该方法通常无论如何都没有明确StackMapTable的,因此您不会遇到这个问题(除非该方法具有您的仪器删除的分支)。

StackMapTable另一个结论是,如果您将类文件版本号修补为以下 值,您可以摆脱删除50。当然,这只是一个解决方案,如果您不需要版本50或更新版本中引入的任何类文件功能……</p>

有一个宽限期,JVM 支持对带有损坏StackMapTables 的类文件的回退模式,仅适用于像您这样的场景,其中工具支持不是最新的。(请参阅-XX:+FailoverToOldVerifier-XX:-UseSplitVerifier)但是现在宽限期已经结束并且该支持已被拒绝,即 Java 8 JVM 不再支持回退模式。

如果您想跟上 Java 开发和检测可能使用这些新版本功能的较新类文件,您只有两个选择:

  • StackMapTable手动计算正确
  • 使用支持计算正确StackMapTable属性的工具,例如ASM(参见)确实支持它
于 2014-10-20T11:13:22.540 回答