【问题标题】:Incompatible argument to function with ASM bytecode instrumentation与 ASM 字节码检测功能不兼容的参数
【发布时间】:2012-12-18 19:13:59
【问题描述】:

我在使用 Guava 库运行一个简单的主程序时遇到了一些麻烦。

我已经使用我的代码从这里检测类以获取方法参数:Java method parameters values in ASM

问题是,虽然代码适用于小型项目(又名河内塔),但使用 Guava 我有错误和异常。

特别是在测试 Joiner.join 方法的时候,出现这个错误:

Exception in thread "Jalen Agent" java.lang.VerifyError: (class: com/google/common/base/Joiner, method: withKeyValueSeparator signature: (Ljava/lang/String;)Lcom/google/common/base/Joiner$MapJoiner;) Incompatible argument to function
at Main.joinBench(Main.java:42)
at Main.main(Main.java:20)

当使用 -noverify 运行示例时,我遇到了一个异常:

Exception in thread "Jalen Agent" java.lang.ArrayIndexOutOfBoundsException: 1
at com.google.common.base.Joiner.<init>(Joiner.java)
at com.google.common.base.Joiner.on(Joiner.java:71)
at Main.joinBench(Main.java:42)
at Main.main(Main.java:20)

方法的字节码是一致的:

  public static com.google.common.base.Joiner on(java.lang.String);
      Code:
         0: bipush        1
         2: anewarray     #4                  // class java/lang/Object
         5: astore_1      
         6: aload_1       
         7: bipush        0
         9: aload_0       
        10: aastore       
        11: ldc           #20                 // int 369
        13: ldc           #21                 // String com/google/common/base/Joiner
        15: ldc           #22                 // String on
        17: aload_1       
        18: invokestatic  #28                 // Method jalen/MethodStats.onMethodEntry:(ILjava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V
        21: new           #2                  // class com/google/common/base/Joiner
        24: dup           
        25: aload_0       
        26: invokespecial #32                 // Method "<init>":(Ljava/lang/String;)V
        29: ldc           #20                 // int 369
        31: invokestatic  #36                 // Method jalen/MethodStats.onMethodExit:(I)V
        34: areturn

我了解该错误可能与库版本有关,但主要 java 程序是针对已检测的库编译并使用该库的同一 jar 运行的。

关于为什么会发生这种情况的任何想法?以及如何解决?

谢谢:)

编辑

这里是方法 withKeyValueSeparator 检测前后的字节码

原始字节码:

public com.google.common.base.Joiner$MapJoiner withKeyValueSeparator(java.lang.String);
Code:
   0: new           #33                 // class com/google/common/base/Joiner$MapJoiner
   3: dup           
   4: aload_0       
   5: aload_1       
   6: aconst_null   
   7: invokespecial #34                 // Method com/google/common/base/Joiner$MapJoiner."<init>":(Lcom/google/common/base/Joiner;Ljava/lang/String;Lcom/google/common/base/Joiner$1;)V
  10: areturn

检测字节码:

public com.google.common.base.Joiner$MapJoiner withKeyValueSeparator(java.lang.String);
Code:
   0: bipush        1
   2: anewarray     #4                  // class java/lang/Object
   5: astore_1      
   6: aload_1       
   7: bipush        1
   9: aload_1       
  10: aastore       
  11: ldc           #199                // int 390
  13: ldc           #21                 // String com/google/common/base/Joiner
  15: ldc           #200                // String withKeyValueSeparator
  17: aload_1       
  18: invokestatic  #28                 // Method jalen/MethodStats.onMethodEntry:(ILjava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V
  21: new           #8                  // class com/google/common/base/Joiner$MapJoiner
  24: dup           
  25: aload_0       
  26: aload_1       
  27: aconst_null   
  28: invokespecial #203                // Method com/google/common/base/Joiner$MapJoiner."<init>":(Lcom/google/common/base/Joiner;Ljava/lang/String;Lcom/google/common/base/Joiner$1;)V
  31: ldc           #199                // int 390
  33: invokestatic  #36                 // Method jalen/MethodStats.onMethodExit:(I)V
  36: areturn 

这里是joiner类的完整字节码:

原文:http://pastebin.com/VsccVX18

仪表:http://pastebin.com/xtke1a8y

【问题讨论】:

  • 您能否将-v 标志添加到您的javap 命令中?前者打印了一些其他有用的信息,可能会有所帮助。

标签: java bytecode java-bytecode-asm bytecode-manipulation verifyerror


【解决方案1】:

首先,我不明白为什么这应该与库版本有关。似乎字节码没有正确检测,如果使用 -noverify 会导致验证失败和异常。

关于校验错误,说明Joiner.withKeyValueSeparator()有错误。此方法的代码尝试使用不兼容的方法参数调用另一个方法。你能给出 withKeyValueSeparator() 方法的检测字节码吗? (最好是非仪表)

你用 -noverify 看到的错误发生在 Joiner 的构造函数中,Joiner.on() 方法似乎没有任何问题。同样,您能否发布 Joiner 的字节码。方法? (仪表和非仪表)

【讨论】:

  • 嗨,感谢您的见解 :) 。我添加了 withKeyValueSeparator 方法的字节码,包括原始的和检测的。我还添加了该类的 pastebin(也在 2 版本中)。
【解决方案2】:

withKeyValueSeparator 的原始代码将一组参数传递给MapJoiner 构造函数。您正在添加将数组存储在局部变量表的第二个槽中的检测代码(使用astore_1)。这将覆盖withKeyValueSeparator 的第一个参数,即String。 (局部变量表的第一个槽是MapJoiner 实例本身,又名this。)因此,当原始函数的代码尝试将局部变量表的第二个槽中的对象传递给构造函数时,就会出现“不兼容的参数”错误。

要解决这个问题,您应该在局部变量表中为您的数组分配一个新槽; this answer 概述了方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-06
    • 1970-01-01
    • 2020-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多