我正在尝试通过在特定指令之前插入调用来修改方法。 似乎我的检测会导致一个不同的stackmap表,而bcel包本身不能自动生成它。 因此,我的检测类文件包含旧的stackmap表,这将导致jvm错误。 我尝试过removeCodeAttributes,MethodGen的方法,可以删除所有的代码属性。它可以在简单的情况下工作,例如包装函数。现在它不适用于我的情况。
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();
}
}
答案 0 :(得分:2)
删除StackMapTable
不是解决错误StackMapTable
的正确解决方案。重要的引用是:
4.7.4. The StackMapTable Attribute
在版本号为50.0或更高版本的
class
文件中,如果方法的Code
属性没有StackMapTable
属性,则它具有隐式堆栈映射属性< / em>(§4.10.1)。此隐式堆栈映射属性等同于StackMapTable
属性,number_of_entries
等于零。
由于StackMapTable
必须为每个分支目标都有显式条目,因此这种隐式StackMapTable
仅适用于无分支方法。但在这些情况下,该方法通常没有明确的StackMapTable
,因此您不会遇到该问题(除非该方法具有您的仪器删除的分支)。
另一个结论是,如果将类文件版本号修改为 StackMapTable
以下的值,则可以删除50
。当然,如果您不需要版本50
或更新版本中引入的任何类文件功能,这只是一种解决方案...
有一个宽限期,JVM支持具有损坏StackMapTable
的类文件的后备模式,仅适用于像您这样的情况,其中工具支持不是最新的。 (请参阅-XX:+FailoverToOldVerifier
或-XX:-UseSplitVerifier
)但宽限期现已结束且支持已被拒绝,即Java 8 JVM不再支持回退模式。
如果您想了解可能使用这些新版本功能的Java开发和仪器新类文件,您只有两个选择:
StackMapTable
StackMapTable
属性的工具,例如ASM
,(请参阅java-bytecode-asm)确实支持