Search code examples
javajava-bytecode-asm

ASM COMPUTE_MAXS not working for basic test case?


At the bottom of the post is the test case. It gives the following error. But I have set new ClassWriter(ClassWriter.COMPUTE_MAXS) so shouldn't it be automatically calculating the max stack and setting it properly?

Exception in thread "main" java.lang.RuntimeException: Error at instruction 2: Insufficient maximum stack size. testMethod()Ljava/lang/Object;
00000  :  :    L0
00001  :  :     LINENUMBER 22 L0
00002  :  :     ACONST_NULL
00003 ? :     ARETURN

Test case:

public static void main(String[] args) {
    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
    CheckClassAdapter cv = new CheckClassAdapter(cw);
    cv.visit(V1_7, ACC_PUBLIC + ACC_SUPER, "path/Cls", null, "java/lang/Object", null);
    {
        MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
        mv.visitCode();
        Label l0 = new Label();
        mv.visitLabel(l0);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
        mv.visitInsn(RETURN);
        Label l1 = new Label();
        mv.visitLabel(l1);
        mv.visitLocalVariable("this", "L" + "path/Cls" + ";", null, l0, l1, 0);
        mv.visitMaxs(1, 1);
        mv.visitEnd();
    }
    {
        MethodVisitor mv = cv
                .visitMethod(ACC_PUBLIC + ACC_STATIC, "testMethod", "()Ljava/lang/Object;", null, null);
        mv.visitCode();
        Label l0 = new Label();
        mv.visitLabel(l0);
        mv.visitLineNumber(22, l0);
        mv.visitInsn(ACONST_NULL);
        mv.visitInsn(ARETURN);
        mv.visitMaxs(0, 0); // Same error even if this is commented out
        mv.visitEnd();
    }

    byte[] byteArray = cw.toByteArray();
}

Solution

  • The problem is not in ASM, but in your test. Basically the CheckClassAdapter is seeing bytecode before max stack and var values are calculated.

    You can change code to something like this:

      ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
      cw.visit...
    
      byte[] byteArray = cw.toByteArray();
      ClassReader cr = new ClassReader(byteArray);
      cr.accept(new CheckClassAdapter(new ClassWriter(0)), 0);