【发布时间】:2016-10-31 16:10:41
【问题描述】:
我有一个稍微复杂的架构,我尝试使用 JVMTI 函数 RetransformClasses 和事件挂钩 ClassLoadFileHook 来检测一个类,同时使用 JNI 进入 Java 空间以执行转换。在ClassLoadFileHook 中,我检查它是否正在为我要检测的类触发,如果是,我对Java 类进行JNI 调用,在该类中我使用ASM 5.0.4 执行检测。也就是说,在 Java 空间中,我得到一个表示检测类的字节数组,然后回调到我的本机代码以应用更新。
我遇到的问题是,在我重新转换类的 Java 代码中,代码在实例化 ClassReader 期间/之后挂起:
/**
* Transform some class and then call back down to native code to apply
* the transformation.
*
* @param existingClass The existing class to change.
*/
public synchronized void transformSomeClass(byte[] existingClass) {
System.out.println("Transformation function started. Existing class len: " + existingClass.length);
try {
ClassReader cr = new ClassReader(existingClass);
// No statements below here are being executed.
// I'm also not sure if `new ClassReader` is being successfully
// executed.
System.out.println("After ClassReader instantiation");
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
System.out.println("After ClassWriter instantiation");
ClassVisitor cv =
new MyCustomClassAdapter(cw, this.lineNumberToPlaceUpdate_);
System.out.println("After ClassVisitor instantiation");
cr.accept(cv, 0);
System.out.println("After cv accept.");
System.out.println("Applying class transformation natively.");
// Call back down to native code to apply the update in ClassLoadFileHook.
applyClassTransformNative(cw.toByteArray());
System.out.println("Transformation function ended.");
} catch (Exception e) {
// This is never being fired.
System.err.println("Class transformation could not be completed. Error message: " + e.getMessage());
e.printStackTrace();
} finally {
// This print statement is never executed.
System.err.println("Going back to native code from finally");
}
}
正如我在代码的 cmets 中提到的,ClassReader intantiation 语句之后没有任何内容被执行。甚至finally 块也没有被执行。我不确定这里会发生什么——为什么实例化一个采用通用字节数组的ClassReader 会导致代码像这样挂起?我实际上并没有对类执行任何操作。
【问题讨论】:
-
对于任何想知道为什么我不确定
new ClassReader是否没有返回/为什么我不使用调试器的人的旁注——我正在进行的 JNI 调用来自我正在编写的代理,据我所知,我没有使用调试器的奢侈,因为 java 进程只能运行一个代理。如果我弄错了,我当然会感谢有人解释原因,并告诉我如何使用调试器。 -
我假设您正在触发一个类加载,它隐式锁定正在加载 ASM 类的类加载器。因此,您的代码永远不会进步。否则,你会得到你的输出。
-
“一个java进程只能运行一个代理”?我从来没有听说过这样的限制。可以肯定的是,我只是对其进行了测试,并且运行多个代理没有问题……
-
此外,您确定实现一个必须调用 Java 空间以执行其实际工作的本机代理是正确的方法吗?为什么不首先实现 Java 代理?
-
@RafaelWinterhalter 你是对的。谢谢!如果您想对此问题添加答案,我很乐意将其标记为正确。
标签: java java-native-interface bytecode java-bytecode-asm javaagents