gpt4 book ai didi

java - 如何使用 java agent 和 ASM 监控对象创建?

转载 作者:行者123 更新时间:2023-12-05 09:09:19 26 4
gpt4 key购买 nike

我想做的是监控对象创建并记录该对象的唯一 ID。

首先我尝试监控 NEW指令但它不能工作并抛出VerifyError: (...) Expecting to find object/array on stack .听说NEW之后的对象未初始化,因此不能传递给其他方法。所以我放弃了这种方法。

其次,我尝试监控 <init> 的调用,此方法初始化未初始化的对象。但是我不确定初始化后,是否会将初始化后的对象压入栈中?

在我的访问者适配器方法中:

public void visitMethodInsn(int opc, String owner, String name, String desc, boolean isInterface) {
...
mv.visitMethodInsn(opc, owner, name, desc, isInterface);
if (opc == INVOKESPECIAL && name.equals("<init>")) {
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESTATIC, "org/myekstazi/agent/PurityRecorder", "object_new",
"(Ljava/lang/Object;)V", false);
}
}

MyRecorder.java :

public static void object_new(Object ref){
log("object_new !");
log("MyRecorder: " + ref);
log("ref.getClass().getName(): " + ref.getClass().getName());
}

我在演示中尝试过它们,它抛出 VerifyError :

Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.VerifyError: Operand stack underflow
Exception Details:
Location:
AbstractDemo.<init>()V @4: dup
Reason:
Attempt to pop empty stack.
Current Frame:
bci: @4
flags: { }
locals: { 'AbstractDemo' }
stack: { }
Bytecode:
0x0000000: 2ab7 0001 59b8 003b b1

at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Unknown Source)
at java.lang.Class.privateGetMethodRecursive(Unknown Source)
at java.lang.Class.getMethod0(Unknown Source)
at java.lang.Class.getMethod(Unknown Source)
at sun.launcher.LauncherHelper.validateMainClass(Unknown Source)
at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source)

好像不太好用。是否有任何替代方法来监视对象创建?

最佳答案

消息部分

Location:
AbstractDemo.<init>()V @4: dup

提示:您正在检测构造函数。在构造函数中,invokespecial <init>也用于委托(delegate)给同一个类或父类(super class)中的另一个构造函数。

调用另一个构造函数的典型顺序是 aload_0 (这个),推送参数,invokespecial <init> , 因此在调用之后没有对堆栈中对象的引用。

这就是 VerifyError 的解码字节码看起来像:

  0 aload_0
1 invokespecial [1]
4 dup
5 invokestatic [59]
8 return

通常,您不想报告这些委托(delegate)构造函数调用,因为它们会导致多次报告同一对象。但是识别它们可能很棘手,因为接收器类不是一个可靠的标准。例如,以下是有效的 Java 代码:

public class Example {
Example reference;
Example(Example anotherObject) {
reference = anotherObject;
}
Example() {
this(new Example(null));
reference.reference = new Example(this);
}
}

在这里,我们有一个包含三个 invokespecial 的构造函数具有相同目标类的指令和委托(delegate)构造函数调用既不是第一个也不是最后一个,因此指令本身没有易于检查的属性告诉您这一点。您必须将提供指令的目标标识为 aload索引为零,即 this , 了解一条指令是否正在初始化当前实例,当中间有参数提供指令时,这很重要。

也就是说,即使在构造函数之外,也无法保证新实例化的对象在堆栈中。当实例化用于随后存储或使用结果的表达式上下文中而不是语句上下文中时,通常是这种情况。换句话说,对于像

这样的方法
void test() {
new Example();
}

朴素的编译器实现(如 javac )可能会生成与表达式代码等效的代码,后跟 pop。指令,但其他实现(如 ecj )可以省略前面的 dup在这种情况下,无需后续 pop ,因为在 invokespecial <init> 之后堆栈上没有引用说明。

更安全的方法是搜索以new 开头的指令序列并导致 invokespecial <init> (允许嵌套出现)。然后,注入(inject) dupnew 之后指令和 invokestaticinvokespecial之后.

关于java - 如何使用 java agent 和 ASM 监控对象创建?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62506802/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com