Computing maximum stack size does not work correctly with JSR/RET instructions present
Commenting in the ACONST_NULL and POP instructions should mean that the maximum stack size is at least two, but one is computed.
With mv.visitMaxs(5, 0);
, the verify error is thrown with ASM 6.1, but not with ASM 6.0. This is most likely caused by
the computation of maximum stack size no longer taking the passed parameter into account with COMPUTE_MAXS present.
With mv.visitMaxs(0, 0)
, the class verification fails with both versions.
This is distilled down version of com/sun/corba/ee/impl/protocol/CorbaClientDelegateImpl
from GlassFish 2.
import static org.objectweb.asm.Opcodes.*;
import java.util.Arrays;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
public class TestCase {
public static void main(String[] args){
byte[] bytes = dumpBytes();
Class test = new ClassLoader() {
public Class<?> defineClass(String name, byte[] bytes) {
return defineClass(name, bytes, 0, bytes.length, null);
}
}.defineClass("test.Test", bytes);
System.out.println(Arrays.toString(test.getDeclaredMethods()));
}
public static byte[] dumpBytes() {
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
MethodVisitor mv;
cw.visit(V1_5, ACC_PUBLIC + ACC_SUPER, "test/Test", null, "java/lang/Object", null);
{
mv = cw.visitMethod(ACC_PUBLIC, "test", "()Ljava/lang/Object;", null, null);
mv.visitCode();
Label l0 = new Label();
Label l1 = new Label();
Label l2 = new Label();
mv.visitTryCatchBlock(l0, l1, l2, null);
Label l3 = new Label();
mv.visitTryCatchBlock(l2, l3, l2, null);
Label l4 = new Label();
Label l5 = new Label();
mv.visitTryCatchBlock(l0, l4, l5, "java/lang/RuntimeException");
Label l6 = new Label();
Label l7 = new Label();
mv.visitTryCatchBlock(l0, l6, l7, null);
Label l8 = new Label();
mv.visitTryCatchBlock(l7, l8, l7, null);
mv.visitLabel(l0);
Label l9 = new Label();
mv.visitJumpInsn(JSR, l9);
mv.visitLabel(l1);
Label l10 = new Label();
mv.visitJumpInsn(GOTO, l10);
mv.visitLabel(l2);
mv.visitInsn(POP);
mv.visitJumpInsn(JSR, l9);
mv.visitLabel(l3);
mv.visitInsn(ACONST_NULL);
mv.visitInsn(ATHROW);
mv.visitLabel(l9);
mv.visitVarInsn(ASTORE, 10);
mv.visitVarInsn(RET, 10);
mv.visitLabel(l10);
mv.visitInsn(ACONST_NULL);
// Comment in the following block to reproduce the issue
{
// mv.visitInsn(ACONST_NULL);
// mv.visitInsn(ACONST_NULL);
// mv.visitInsn(POP);
// mv.visitInsn(POP);
}
mv.visitInsn(POP);
mv.visitLabel(l4);
Label l13 = new Label();
mv.visitJumpInsn(GOTO, l13);
mv.visitLabel(l5);
mv.visitInsn(POP);
mv.visitJumpInsn(GOTO, l13);
mv.visitInsn(ACONST_NULL);
mv.visitInsn(ATHROW);
mv.visitLabel(l13);
mv.visitInsn(ICONST_0);
mv.visitJumpInsn(IFNE, l0);
Label l14 = new Label();
mv.visitJumpInsn(JSR, l14);
mv.visitLabel(l6);
mv.visitInsn(ACONST_NULL);
mv.visitInsn(ARETURN);
mv.visitLabel(l7);
mv.visitInsn(POP);
mv.visitJumpInsn(JSR, l14);
mv.visitLabel(l8);
mv.visitInsn(ACONST_NULL);
mv.visitInsn(ATHROW);
mv.visitLabel(l14);
mv.visitVarInsn(ASTORE, 12);
mv.visitVarInsn(RET, 12);
mv.visitMaxs(5, 0);
// mv.visitMaxs(0, 0);
mv.visitEnd();
}
cw.visitEnd();
return cw.toByteArray();
}
}