5

I am having some troubles running a simple main program with Guava libraries.

I have instrumented the classes to get the methods parameters using my code from here : Java method parameters values in ASM

The issue is, that while the code works for small projects (aka Tower of Hanoi), with Guava I have errors and exceptions.

In particular, when testing the Joiner.join method, I have this error:

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)

And when running the example using -noverify, I have an exception:

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)

The bytecode of the method is consistent:

  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

I understand that the error may be related to libraries version, but the main java program was compiled against the instrumented library and run using the same jar of the library.

Any ideas on why this is happening? And how it can be solved?

Thanks :)

EDIT

Here are the bytecode of the method withKeyValueSeparator before and after instrumentation

Original bytecode:

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

Instrumented bytecode:

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 

Here are the full bytecode of the joiner class :

Original : http://pastebin.com/VsccVX18

Instrumented : http://pastebin.com/xtke1a8y

Community
  • 1
  • 1
Adel
  • 441
  • 1
  • 5
  • 14
  • Could you add the `-v` flag to your `javap` command? The former prints some other useful information that could help. – Xyene Feb 20 '13 at 23:56

2 Answers2

1

The original code of withKeyValueSeparator passes a bunch of its arguments to the MapJoiner constructor. You're adding instrumentation code that stores an array in the second slot of the local variable table (using astore_1). This overwrites the first argument to withKeyValueSeparator, which is a String. (The first slot of the local variable table is a MapJoiner instance itself, a.k.a this.) So when the original function's code tries to pass the object in the second slot of the local var table to the constructor, there is that "Incompatible argument" error.

To fix this, you should allocate a new slot in the local variable table for your array; this answer outlines how.

Community
  • 1
  • 1
int3
  • 12,861
  • 8
  • 51
  • 80
0

First, I do not see why this should be related to libraries versions. It seems that the bytecode is not instrumented correctly, which causes the verification to fail and the exception if you use -noverify.

Regarding the verification error, it indicates that there is an error in Joiner.withKeyValueSeparator(). The code of this method tries to invoke another method with incompatible method arguments. Could you give the instrumented bytecode of the withKeyValueSeparator() method? (and perferrably the non-instrumented as well)

The error you see with -noverify occurs in the constructor of the Joiner, there seems to be nothing wrong with the Joiner.on() method. Again, could you post the bytecode of the Joiner. method? (instrumented and non-instrumented)

ruediste
  • 2,434
  • 1
  • 21
  • 30
  • Hi, thanks for your insights :) . I added the bytecode of the method withKeyValueSeparator, both original and instrumented. I also added a pastebin of the class (also in 2 version). – Adel Jan 07 '13 at 14:27