Construct the stackmap of method while using bcel

风格不统一 提交于 2019-12-08 10:59:59

问题


I am trying bcel to modify a method by inserting invoke before specific instructions. It seems that my instrumentation would result in a different stackmap table, which can not be auto-generated by the bcel package itself. So, my instrumented class file contains the old stackmap table, which would cause error with jvm. I haved tried with removeCodeAttributes, the method of MethodGen, that can remove all the code attributes. It can work in simple cases, a wrapped function, for example. And it can not work in my case now.

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();
    }
}

回答1:


Removing a StackMapTable is not a proper solution for fixing a wrong StackMapTable. The important cite is:

4.7.4. The StackMapTable Attribute

In a class file whose version number is 50.0 or above, if a method's Code attribute does not have a StackMapTable attribute, it has an implicit stack map attribute (§4.10.1). This implicit stack map attribute is equivalent to a StackMapTable attribute with number_of_entries equal to zero.

Since a StackMapTable must have explicit entries for every branch target, such an implicit StackMapTable will work with branch-free methods only. But in these cases, the method usually doesn’t have an explicit StackMapTable anyway, so you wouldn’t have that problem then (unless the method had branches which your instrumentation removed).

Another conclusion is that you can get away with removing the StackMapTable, if you patch the class file version number to a value below 50. Of course, this is only a solution if you don’t need any class file feature introduced in version 50 or newer…

There was a grace period in which JVMs supported a fall-back mode for class files with broken StackMapTables just for scenarios like yours, where the tool support is not up-to-date. (See -XX:+FailoverToOldVerifier or -XX:-UseSplitVerifier) But the grace period is over now and that support has been declined, i.e. Java 8 JVMs do not support the fall-back mode anymore.

If you want to keep up with the Java development and instrument newer class files which might use features of these new versions you have only two choices:

  • Calculate the correct StackMapTable manually
  • Use a tool which supports calculating the correct StackMapTable attributes, e.g. ASM, (see java-bytecode-asm) does support it


来源:https://stackoverflow.com/questions/26072210/construct-the-stackmap-of-method-while-using-bcel

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!