【问题标题】:Java agent : transform() not applied on all classesJava 代理:transform() 未应用于所有类
【发布时间】:2015-12-15 09:49:30
【问题描述】:

我一直在尝试使用 Java 代理通过 ASM 应用字节码转换。

我使用premain 方法实现了一个代理,向仪器添加了一个变压器。 我在 .jar 清单中添加了“Premain-Class”行

Premain-Class: <MyAgentPath>

然后我尝试使用代理运行应用程序。

我有一个问题:我的转换器修改了一些方法调用,所以如果不是所有涉及的类也都被修改了,它就无法工作。还有一些类没有被修改,比如“org.apache.commons.math3.util.FastMath”。 当然,我得到了错误:

java.lang.NoSuchMethodError: org.apache.commons.math3.util.FastMath.floor<new_descriptor>

我查看了很多帖子说它可能是引导加载程序,它不知道此类的路径,所以我尝试使用不同的方式添加它:

  • 在清单中添加“Boot-Class-Path”行:

    Boot-Class-Path: <...>/commons-math3<...>.jar
    
  • 使用方法“appendToBootstrapClassLoaderSearch(JarFile)”

    inst.appendToBootstrapClassLoaderSearch("<...>/commons-math3<...>.jar");
    
  • 使用 JVM 参数“-Xbootclasspath/a:”

    -Xbootclasspath/a:<...>/commons-math3<...>.jar
    

这些都没有改变任何东西。

我还使用 Instrumentation 类方法 getAllLoadedClasses() 来查看加载了哪些类,以及加载了应用程序进程中涉及的所有类,包括 FastMath。

for(Class<?> clazz : MyAgent.getInstInstance().getAllLoadedClasses()){
    buffWrite.write(clazz.getName());

由于“FastMath”类出错并且引导加载程序应该有它的路径,我尝试在同一个包中添加一些对来自其他类的方法的方法调用。似乎问题并没有针对包的每个类显示。

例如:MathUtils 被转换并调用修改后的方法checkFinite(D)V -> checkFinite&lt;new_descriptor&gt;

所以我猜这个问题与提供给引导加载程序的路径无关。

如果您对正在发生的事情有一些想法,我会很高兴听到的!

【问题讨论】:

    标签: java javaagents


    【解决方案1】:

    NoSuchMethodError 很可能不是由于未向引导类加载器添加某些内容而引起的。这可能是一个问题的唯一机会是,如果突然有两个这样的罐子可用,一个被检测,另一个没有。

    如果您调用更改方法checkFinite(D)V 成为另一个方法checkFinite&lt;new_descriptor&gt;,那么您需要确保任何使用FastMath.floor 的类将描述符更新为该方法。这意味着您需要遍历每个类的每个方法,以查找 ASM 的 visitMethodIns 调用。好像你错过了一些。由于您正在更改 FastMath 类的布局,因此您必须在首次加载它时对其进行检测,并且您无法重新定义它

    Java 内部类不知道FastMath,因为这是第三方依赖项。因此,应该可以检测来自您的代理的任何呼叫。在我看来,您正在过早地加载 FastMath

    【讨论】:

    • 你好 Rafael,我不是在问这篇文章中的 NoSuchMethodError,这个错误是由对 FastMath.floor&lt;new_descriptor&gt; 的调用引起的,但是由于 FastMath 类没有被转换,方法 floor 描述符不匹配。如果未转换 FastMath,则会出现此错误。转换工作正常,我已经能够通过扰动的 ClassLoader 转换整个应用程序。但为了方便起见,我更喜欢使用 Java 代理。所以问题不在于 ASM 的使用,而在于 FastMath 没有被转换。
    • 但是你能观察到FastMath 被交给了transformer(记录,断点)。如果你从你的代理中引用 loaded 类,它会被提前加载。否则,它应该可以正常工作。
    • 我在 transform() 方法中添加了断点,以查看FastMath 是否会出现在那里。它没有......我不明白的是为什么代理会加载像 FastMath 这样的类,但不会转换?
    • 如果你加载一个类之前 ClassFileTransformer 就位,它不会被转换。所以我假设这发生在你的代理中。
    • 好吧,这听起来很合乎逻辑,但我使用的是premain 方法而不是agentmain,所以代理应该是JVM 加载的第一个“东西”。此外,使用getAllLoadedClasses()方法,我可以看到FastMath在代码的某个点之前没有加载...for (Class&lt;?&gt; clazz : MyAgent.getInstInstance().getAllLoadedClasses()){ if(clazz.getSimpleName.equals("FastMath")){ //breakpoint } }
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-28
    • 2012-01-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多