bytekit icon indicating copy to clipboard operation
bytekit copied to clipboard

有解决办法吗?当使用@Binding.InvokeArgs Object[] args时抛异常,急需使用,感谢求解~~

Open b97y opened this issue 2 years ago • 10 comments

java.lang.IllegalArgumentException: Error at instruction 21: Expected an object reference, but found . test()V 00000 R . . . : : L0 00001 R . . . : : LINENUMBER 23 L0 00002 R . . . : : NEW com/alibaba/bytekit/asm/interceptor/AtInvokeTest2$Sample 00003 R . . . : R : DUP 00004 R . . . : R R : INVOKESPECIAL com/alibaba/bytekit/asm/interceptor/AtInvokeTest2$Sample. ()V 00005 R . . . : R : ASTORE 1 00006 R R . . : : L1 00007 R R . . : : LINENUMBER 24 L1 00008 R R . . : : ICONST_0 00009 R R . . : I : ISTORE 2 00010 R R I . : : L2 00011 R R I . : : FRAME APPEND [com/alibaba/bytekit/asm/interceptor/AtInvokeTest2$Sample I] 00012 R R I . : : ILOAD 2 00013 R R I . : I : ICONST_1 00014 R R I . : I I : IF_ICMPGE L3 00015 R R I . : : L4 00016 R R I . : : LINENUMBER 25 L4 00017 R R I . : : ALOAD 1 00018 R R I . : R : LDC "hello2" 00019 R R I . : R R : ILOAD 2 00020 R R I . : R R I : LDC "hello" 00021 R R I . : R R I R : ALOAD 3 00022 ? : INVOKESTATIC com/alibaba/bytekit/asm/interceptor/AtInvokeTest2$TestAccessInterceptor.onInvoke (Ljava/lang/String;[Ljava/lang/Object;)V 00023 ? : INVOKEVIRTUAL com/alibaba/bytekit/asm/interceptor/AtInvokeTest2$Sample.hello (Ljava/lang/String;I)Ljava/lang/String; 00024 ? : POP 00025 ? : L5 00026 ? : LINENUMBER 24 L5 00027 ? : IINC 2 1 00028 ? : GOTO L2 00029 R R I . : : L3 00030 R R I . : : LINENUMBER 27 L3 00031 R R I . : : FRAME SAME 00032 R R I . : : RETURN 00033 ? : L6

b97y avatar May 08 '23 13:05 b97y

给出具体的复现demo。

hengyunabc avatar May 10 '23 09:05 hengyunabc

给出具体的复现demo。

运行com.alibaba.bytekit.asm.interceptor.AtInvokeTest2中的testcase就可以复现: image

b97y avatar May 11 '23 01:05 b97y

给出具体的复现demo。

能帮忙解决吗,等着用,感谢

b97y avatar May 16 '23 02:05 b97y

这个测试是有问题,默认应该是不启用的,可以看项目说明,用 mvn命令来执行。

hengyunabc avatar May 17 '23 07:05 hengyunabc

给出具体的复现demo。

能帮忙解决吗,等着用,感谢

请问下您这个问题解决了么?我用@Binding.InvokeReturn也会出错。

fqyugu65 avatar May 29 '23 07:05 fqyugu65

这个测试是有问题,默认应该是不启用的,可以看项目说明,用 mvn命令来执行。

是不是这两个Binding, InvokeRetuer, InvokeArgs现在还不能用呢?

fqyugu65 avatar May 29 '23 08:05 fqyugu65

这个测试是有问题,默认应该是不启用的,可以看项目说明,用 mvn命令来执行。

复现demo:MicroService类中方法interfaceA调用了方法interfaceB,期望得到传入interfaceB的参数值

b97y avatar Jul 13 '23 08:07 b97y

package com.example;

import com.alibaba.bytekit.asm.MethodProcessor;
import com.alibaba.bytekit.asm.binding.Binding;
import com.alibaba.bytekit.asm.interceptor.InterceptorProcessor;
import com.alibaba.bytekit.asm.interceptor.annotation.AtInvoke;
import com.alibaba.bytekit.asm.interceptor.parser.DefaultInterceptorClassParser;
import com.alibaba.bytekit.utils.AgentUtils;
import com.alibaba.bytekit.utils.AsmUtils;
import com.alibaba.bytekit.utils.Decompiler;
import com.alibaba.deps.org.objectweb.asm.tree.ClassNode;
import com.alibaba.deps.org.objectweb.asm.tree.MethodNode;

import java.util.List;
import java.util.concurrent.TimeUnit;

public class InterfaceInvokeDemo {

    public static class MicroService {

        public void interfaceA(String strA){
            System.out.println("interfaceA" + strA);

            String strb  = strA + "BBB";
            interfaceB(strb);
        }

        public void interfaceB(String strB){
            System.out.println("interfaceB" + strB);
        }

    }


    public static class TestAccessInterceptor {
        @AtInvoke(name = "interfaceB", inline = false, whenComplete = false)
        public static void onInvokeAfter(
                @Binding.This Object object,
                @Binding.Class Object clazz,
                @Binding.MethodName String methodName,
                @Binding.InvokeMethodName String invokeMethodName,
                @Binding.InvokeArgs Object[] args,
                @Binding.InvokeReturn Object invokeReturn,
                @Binding.InvokeMethodDeclaration String declaration
        ) {
            System.err.println("onInvokeAfter: this" + object);
            System.err.println("methodName: " + methodName);
            System.err.println("InvokeMethodName: " + invokeMethodName);
            System.err.println("InvokeMethodDeclaration: " + declaration);
        }
    }


    public static void main(String[] args) throws Exception {
        AgentUtils.install();
        // 不断执行
        final MicroService microService = new MicroService();
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 20; ++i) {
                    try {
                        TimeUnit.SECONDS.sleep(5);
                        microService.interfaceA(String.valueOf(i));
                        System.out.println("call interfaceA result");
                    } catch (Throwable e) {
                        System.out.println("exception: " + e.getMessage());
                    }
                }
            }
        });
        thread.start();

        // 拦截器定义
        DefaultInterceptorClassParser defaultInterceptorClassParser = new DefaultInterceptorClassParser();
        List<InterceptorProcessor> interceptorProcessor = defaultInterceptorClassParser.parse(TestAccessInterceptor.class);

        // 加载字节码
        ClassNode classNode = AsmUtils.loadClass(MicroService.class);

        // 通过拦截器对字节码增强
        for (MethodNode methodNode : classNode.methods) {
            if (methodNode.name.equals("interfaceA")) {
                MethodProcessor methodProcessor = new MethodProcessor(classNode, methodNode);
                for (InterceptorProcessor interceptor : interceptorProcessor) {
                    interceptor.process(methodProcessor);
                }
            }
        }

        // 增强后的字节码
        byte[] bytes = AsmUtils.toBytes(classNode);

        // 查看反编译结果
        System.out.println(Decompiler.decompile(bytes));

        // 等待,查看增强前的反编译结果
        TimeUnit.SECONDS.sleep(10);

        // 增强类
        AgentUtils.reTransform(MicroService.class, bytes);
        System.in.read();
    }

}

b97y avatar Jul 13 '23 08:07 b97y

统一说下有问题的原因:

  1. 从原理上来说,获取到 invoke method 前的 args ,想要在 invoke method 之后再取出来。它实际上是保存到了一个临时变量里,也就是一个 数组里
  2. 同时,如果想要获取 invoke method 的返回值,并且在后续获取到,那么它实际上也是保存到了一个 临时变量 里
  3. 但目前这种方式有问题: jvm 会抛异常字节码校验失败 ,可能要在 jvm 启动时增加不要校验字节码的参数
  4. 所以实际上 拦载 invoke method 获取 args / return value 不太成熟
  5. 另外,因为这种操作实际上是对 jvm 调用栈有修改,目前是只支持保存一个 slot ,所以 不能同时保存 invoke method 的 args 和 invoke method return value 。 只能用一个注解。

hengyunabc avatar Jul 14 '23 07:07 hengyunabc

统一说下有问题的原因:

  1. 从原理上来说,获取到 invoke method 前的 args ,想要在 invoke method 之后再取出来。它实际上是保存到了一个临时变量里,也就是一个 数组里
  2. 同时,如果想要获取 invoke method 的返回值,并且在后续获取到,那么它实际上也是保存到了一个 临时变量 里
  3. 但目前这种方式有问题: jvm 会抛异常字节码校验失败 ,可能要在 jvm 启动时增加不要校验字节码的参数
  4. 所以实际上 拦载 invoke method 获取 args / return value 不太成熟
  5. 另外,因为这种操作实际上是对 jvm 调用栈有修改,目前是只支持保存一个 slot ,所以 不能同时保存 invoke method 的 args 和 invoke method return value 。 只能用一个注解。

从测试结果来看,即使只使用invoke method 的 args一个注解,也会出现失败,提示读了未初始化的局部变量:

public static class TestAccessInterceptor {
    @AtInvoke(name = "interfaceB", inline = false, whenComplete = false)
    public static void onInvokeAfter(
            @Binding.This Object object,
            @Binding.Class Object clazz,
            @Binding.MethodName String methodName,
            @Binding.InvokeMethodName String invokeMethodName,
            @Binding.InvokeArgs Object[] args,
            //@Binding.InvokeReturn Object invokeReturn,
            @Binding.InvokeMethodDeclaration String declaration
    ) {
        System.err.println("onInvokeAfter: this" + object);
        System.err.println("methodName: " + methodName);
        System.err.println("InvokeMethodName: " + invokeMethodName);
        System.err.println("InvokeMethodDeclaration: " + declaration);
    }
}

public static class InterfaceInvokeDemo.MicroService { /* * Exception decompiling / public void interfaceA(String strA) { / * This method has failed to decompile. When submitting a bug report, please provide this stack trace, and (if you hold appropriate legal rights) the relevant class file. * * java.lang.IllegalStateException: Invisible function parameters on a non-constructor (or reads of uninitialised local variables). * at org.benf.cfr.reader.bytecode.analysis.opgraph.Op02WithProcessedDataAndRefs.assignSSAIdentifiers(Op02WithProcessedDataAndRefs.java:1637) * at org.benf.cfr.reader.bytecode.analysis.opgraph.Op02WithProcessedDataAndRefs.discoverStorageLiveness(Op02WithProcessedDataAndRefs.java:1877) * at org.benf.cfr.reader.bytecode.CodeAnalyser.getAnalysisInner(CodeAnalyser.java:460) * at org.benf.cfr.reader.bytecode.CodeAnalyser.getAnalysisOrWrapFail(CodeAnalyser.java:278) * at org.benf.cfr.reader.bytecode.CodeAnalyser.getAnalysis(CodeAnalyser.java:201) * at org.benf.cfr.reader.entities.attributes.AttributeCode.analyse(AttributeCode.java:94) * at org.benf.cfr.reader.entities.Method.analyse(Method.java:531) * at org.benf.cfr.reader.entities.ClassFile.analyseMid(ClassFile.java:1042) * at org.benf.cfr.reader.entities.ClassFile.analyseTop(ClassFile.java:929) * at org.benf.cfr.reader.Driver.doClass(Driver.java:84) * at org.benf.cfr.reader.CfrDriverImpl.analyse(CfrDriverImpl.java:75) * at com.alibaba.bytekit.utils.Decompiler.decompile(Decompiler.java:145) * at com.alibaba.bytekit.utils.Decompiler.decompile(Decompiler.java:40) * at com.example.InterfaceInvokeDemo.main(InterfaceInvokeDemo.java:95) */ throw new IllegalStateException("Decompilation failed"); }

public void interfaceB(String strB) {
    System.out.println("interfaceB" + strB);
}

}

Process finished with exit code -1

b97y avatar Jul 19 '23 09:07 b97y