ASM:ClassReader不调用MethodVisitor的方法

时间:2017-11-14 09:17:44

标签: java netbeans bytecode static-analysis java-bytecode-asm

我正在编写一个小工具来使用ASM 5执行字节码的静态分析。我将我的输入Java类提供给ClassReader,它触发自定义ClassVisitor的事件。如果符合某些条件,我的ClassVisitor会覆盖visitMethod以返回我的自定义MethodVisitor,如果不符合,则会覆盖null

问题是,ClassReader从不调用MethodVisitor的方法;我使用NetBeans调试它,我看到访问者被正确返回(它不是null)但仍然执行永远不会进入visitMethodInsn,即使方法指令我正在用于测试的课程。

之前我使用过ASM,但这是我第一次遇到这个问题。

以下是MyClassVisitor.visitMethod的代码:

@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
    InvokeFinder visitor;
    if(condition.isMet()) {
        visitor = new InvokeFinder(api);
        visitor.doStuff();
    } else {
        visitor = null;
    }
    return visitor;
}

这里是InvokeFinder的代码,在执行期间从不输入:

public class InvokeFinder extends MethodVisitor {

    public InvokeFinder(int api) {
        super(api);
    }

    void unrelatedMethod(String parameter) {
        doStuff(parameter);
    }

    @Override
    public void visitMethodInsn(int opcode, String owner, String name, String desc) {
        switch (opcode) {
            case Opcodes.INVOKEVIRTUAL:
            case Opcodes.INVOKESPECIAL:
            case Opcodes.INVOKEDYNAMIC:
                doSomething();
                break;
            case Opcodes.INVOKEINTERFACE:
                doSomethingElse();
                break;
            case Opcodes.INVOKESTATIC:
                doSomethingDifferentAgain();
                break;
            default: break;
        }
    }
}

最后这是我正在测试的类(这不是要执行的,它的唯一目的是编译然后通过我的工具进行分析):

public class MyTestClass{

  public MyTestClass(String s) {
    System.out.println( "Function Name" );
  }

  public static void main(String args[]) {
    CGraph g = new CGraph("entry");

    g.enterBF(new CGVisitor() {
        @Override
        public void nodeOperations(CGraph graph, CGraphNode currentNode) {
            System.out.println("20");
        }

        @Override
        public String getString() {
            throw new UnsupportedOperationException("No string can be returned from this anonymous implementation of CGVisitor.");
        }
    });

    a( 11 );
  }

  public static void a(int n) {
    b( n );
  }

  public static void b(int m) {
    int n;

    if (m >= 10)
      a( m-1 );
    else
      System.out.println(m);
  }
}

我仔细检查了上面的visitMethod方法总是被执行,返回一个非空的InvokeFinder实例,并且这个实例永远不会被执行;如果在InvokeFinder.visitMethodInsn的某些方法中存在调用指令(例如,在方法MyTestClass内),那么在这些条件下a(int)怎么可能永远不会被ClassReader调用?

编辑:进一步调试,我发现ClassReader调用默认的MethodVisitor.visitMethodInsn而不是调用被覆盖的版本InvokeFinder.visitMethodInsn。为什么会这样?

1 个答案:

答案 0 :(得分:0)

原来我改变了ASM的API版本,版本4和5之间MethodVisitor.visitMethodInsn的签名不同。动态绑定不再将其视为最重要的方法。

我可以通过将缺少的参数添加到InvokeFinder.visitMethodInsn来解决这个问题,public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) 的签名现在是

Ext.Ajax.request({
            method: 'POST',
            url: g_globalsFromJsp.contextPath + '/UploadAction0.do',
            params: formData,
            success: function (response, opts) {
                        if (response.status ===200) { // OK
                            //Error Here
                            document.open();
                            document.write(response.responseText);
                            document.close();
                        }
            },
            failure : function(response, opts) {
                //SomeAlertMessage
            }
        })