5

Ho problemi con l'esecuzione di un semplice programma principale con le librerie Guava.Argomento incompatibile per funzionare con la strumentazione bytecode ASM

Ho strumentato le classi per ottenere i parametri di metodi utilizzando il mio codice da qui: Java method parameters values in ASM

Il problema è che, mentre il codice funziona per i piccoli progetti (aka Torre di Hanoi), con Guava ho errori e eccezioni.

In particolare, durante il test del metodo Joiner.join, ho questo errore:

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) 

E quando si esegue l'esempio utilizzando -noverify, ho un'eccezione:

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) 

Il codice byte del metodo è coerente:

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 

Capisco che l'errore possa essere correlato alla libreria versione ies, ma il programma java principale è stato compilato contro la libreria strumentata ed eseguito usando lo stesso jar della libreria.

Qualche idea sul perché questo sta accadendo? E come può essere risolto?

Grazie :)

EDIT

Ecco il bytecode del metodo withKeyValueSeparator prima e dopo la strumentazione

bytecode originale:

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 

strumentato 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 

Ecco la piena bytecode della classe falegname:

originale: http://pastebin.com/VsccVX18

Instrumented: http://pastebin.com/xtke1a8y

+0

Potresti aggiungere il flag '-v' al comando' javap'? Il primo stampa alcune altre informazioni utili che potrebbero aiutare. – Xyene

risposta

0

In primo luogo, non vedo perché questo dovrebbe essere correlato a versioni biblioteche. Sembra che il bytecode non sia strumentato correttamente, il che fa fallire la verifica e l'eccezione se si usa -noverify.

Riguardo all'errore di verifica, indica che c'è un errore in Joiner.withKeyValueSeparator(). Il codice di questo metodo tenta di richiamare un altro metodo con argomenti di metodo incompatibili. Potresti fornire il bytecode instrumentato del metodo withKeyValueSeparator()? (e perferenzialmente anche non strumentato)

L'errore che si vede con -noverify si verifica nel costruttore del Joiner, non sembra esserci nulla di sbagliato nel metodo Joiner.on(). Di nuovo, potresti pubblicare il bytecode del Joiner. metodo? (strumentato e non strumentato)

+0

Ciao, grazie per i tuoi approfondimenti :). Ho aggiunto il bytecode del metodo conKeyValueSeparator, sia originale che strumentato. Ho anche aggiunto un pastebin della classe (anche nella versione 2). – Adel

1

Il codice originale di withKeyValueSeparator passa un gruppo di argomenti al costruttore MapJoiner.Stai aggiungendo il codice della strumentazione che memorizza una matrice nel secondo slot della tabella delle variabili locali (utilizzando astore_1). Questo sovrascrive il primo argomento a withKeyValueSeparator, che è un String. (Il primo slot della tabella delle variabili locali è un'istanza , ovvero this.) Quindi, quando il codice della funzione originale tenta di passare l'oggetto nel secondo slot della tabella var locale al costruttore, c'è "Argomento incompatibile" errore.

Per risolvere questo problema, è necessario allocare un nuovo slot nella tabella delle variabili locali per l'array; this answer delinea come.