我在使用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程序是针对已检测的库编译的,并使用相同的库运行。
有关为何发生这种情况的任何想法?它是如何解决的?
谢谢:)
修改
以下是在检测之前和之后使用KeyValueSeparator的方法的字节码
原始字节码:
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类的完整字节码:
答案 0 :(得分:1)
withKeyValueSeparator
的原始代码将一堆参数传递给MapJoiner
构造函数。您正在添加将数组存储在局部变量表的第二个槽中的检测代码(使用astore_1
)。这会将第一个参数覆盖为withKeyValueSeparator
,即String
。 (局部变量表的第一个插槽本身是MapJoiner
实例,也就是this
。)因此,当原始函数的代码尝试将本地var表的第二个插槽中的对象传递给构造函数时,有“不兼容的论证”错误。
要解决此问题,您应该在数组的本地变量表中分配一个新插槽; this answer概述了如何。
答案 1 :(得分:0)
首先,我不明白为什么这应该与库版本有关。似乎没有正确检测字节码,这会导致验证失败,如果使用-noverify则会导致异常。
关于验证错误,它表示Joiner.withKeyValueSeparator()中存在错误。此方法的代码尝试使用不兼容的方法参数调用另一个方法。你能给出withKeyValueSeparator()方法的检测字节码吗? (并且也可以是非仪器化的)
使用-noverify看到的错误发生在Joiner的构造函数中,Joiner.on()方法似乎没有任何问题。再次,您可以发布Joiner的字节码。方法? (仪表化和非仪表化)