问题描述
使用 ASM 创建类时,可以方便地将无意义的值传递给 visitMaxs
public static byte[] createClassNoAdapter() {
var cw = new ClassWriter(ClassWriter.COmpuTE_FRAMES);
cw.visit(Opcodes.V9,ACC_PUBLIC,"TestClass",null,"java/lang/Object",new String[0]);
var mv = cw.visitMethod(ACC_PUBLIC,"test","()V",null);
mv.visitCode();
mv.visitInsn(Opcodes.RETURN);
mv.visitMaxs(-1,-1);
mv.visitEnd();
return cw.toByteArray();
}
但是,我正在尝试诊断一些问题,并使用 CheckClassAdapter
。如果我为 maxStack
和 maxLocals
明确传递正确的值,这会起作用。
public static byte[] createClassAdapter() {
var cw = new ClassWriter(ClassWriter.COmpuTE_FRAMES);
var cv = new CheckClassAdapter(cw);
cv.visit(Opcodes.V9,"TestClass2",new String[0]);
var mv = cv.visitMethod(ACC_PUBLIC,null);
mv.visitCode();
mv.visitInsn(Opcodes.RETURN);
mv.visitMaxs(1,1);
mv.visitEnd();
return cw.toByteArray();
}
虽然这有效,但不太方便。调用 visitMaxs(-1,-1)
会导致错误:
java.lang.IllegalArgumentException: Invalid max stack (must be an unsigned short): -1
at org.objectweb.asm.util.CheckMethodAdapter.checkUnsignedShort(CheckMethodAdapter.java:1133)
at org.objectweb.asm.util.CheckMethodAdapter.visitMaxs(CheckMethodAdapter.java:1027)
at com.justinblank.strings.Example.createClassAdapter(Example.java:35)
at com.justinblank.strings.Example.main(Example.java:47)
源代码清楚地表明您必须传递一个非负值,但传递 0 也不起作用:
java.lang.IllegalArgumentException: Data flow checking option requires valid,non zero maxLocals and maxStack.
at org.objectweb.asm.util.CheckMethodAdapter$1.visitEnd(CheckMethodAdapter.java:456)
at org.objectweb.asm.MethodVisitor.visitEnd(MethodVisitor.java:783)
at org.objectweb.asm.util.CheckMethodAdapter.visitEnd(CheckMethodAdapter.java:1036)
at com.justinblank.strings.Example.createClassAdapterZero(Example.java:51)
at com.justinblank.strings.Example.main(Example.java:65)
Caused by: java.lang.indexoutofboundsexception: Trying to set an inexistant local variable 0
at org.objectweb.asm.tree.analysis.Frame.setLocal(Frame.java:208)
at org.objectweb.asm.tree.analysis.Analyzer.computeInitialFrame(Analyzer.java:466)
at org.objectweb.asm.tree.analysis.Analyzer.analyze(Analyzer.java:163)
at org.objectweb.asm.util.CheckMethodAdapter$1.visitEnd(CheckMethodAdapter.java:453)
... 4 more
有什么方法可以避免在使用 CheckClassAdapter 时手动计算堆栈?
解决方法
看起来使用非常大的值是安全的。在几种情况下,以下值似乎对我有用:
public static byte[] createClassAdapterHacky() {
var cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
var cv = new CheckClassAdapter(cw);
cv.visit(Opcodes.V9,ACC_PUBLIC,"TestClass3",null,"java/lang/Object",new String[0]);
var mv = cv.visitMethod(ACC_PUBLIC,"test","()V",null);
mv.visitCode();
mv.visitMaxs(Short.MAX_VALUE * 2 + 1,Short.MAX_VALUE * 2 + 1);
mv.visitEnd();
return cw.toByteArray();
}
我不确定这是否是正确的解决方案,但它似乎有效。