Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
b97y opened this issue May 8, 2023 · 10 comments

Comments

@b97y
Copy link

b97y commented May 8, 2023

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

@hengyunabc
Copy link
Collaborator

给出具体的复现demo。

@b97y
Copy link
Author

b97y commented May 11, 2023

给出具体的复现demo。

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

@b97y
Copy link
Author

b97y commented May 16, 2023

给出具体的复现demo。

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

@hengyunabc
Copy link
Collaborator

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

@fqyugu65
Copy link

给出具体的复现demo。

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

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

@fqyugu65
Copy link

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

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

@b97y
Copy link
Author

b97y commented Jul 13, 2023

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

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

@b97y
Copy link
Author

b97y commented Jul 13, 2023

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();
    }

}

@hengyunabc
Copy link
Collaborator

统一说下有问题的原因:

  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 。 只能用一个注解。

@b97y
Copy link
Author

b97y commented Jul 19, 2023

统一说下有问题的原因:

  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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants