ClassCastException causato da bug in Just In Time?
-
19-09-2019 - |
Domanda
Dato questo pezzo di codice:
public static void writeFile(File file,List buffer)throws IOException{
File fic = new File(file.getCanonicalPath());
cat.debug("writing file : "+fic.getAbsolutePath());
FileOutputStream out = new FileOutputStream(fic);
PrintStream ps = new PrintStream(out);
for(int i=0;i<buffer.size();i++){
ps.println(buffer.get(i));
}
ps.flush();
ps.close();
out.close();
}
(si prega di nessun consiglio su come chiudere i flussi in modo sicuro, questo è il codice legacy e la nuova versione si avvale di try / finally)
ho un ClassCastException al "ps.println (BUFFER.GET (i))"
Questo metodo viene chiamato più volte (diciamo 5 volte) con un elenco riempito solo con le stringhe quindi, è chiamato con una lista riempito con String e un altro oggetto (dire ErrorObject) Al punto raggiungiamo il primo ErrorObject, otteniamo la ClassCastException.
com.mycompany.ErrorObject incompatible with java.lang.String
Questo problema si verifica in ambiente di produzione, ma non può essere riprodotto in ambiente dev: Prod: jvm = IBM J9 VM 2.4 J2RE 1.6.0 IBM J9 2.4 AIX ppc-32 jvmap3260-20081105_25433 (JIT abilitato, AOT abilitata) Dev: WinXP, JDK 1.6.0_16
C'è un motivo questo codice potrebbe fallire?
E 'stato patchato da poco, temo che il team di produzione non aggiornare il vaso in modo corretto, ma il mio capo già verificato che la patch è stata applicata correclty ...
Mi chiedevo se il Just in Time compilatore potrebbe "filo" la ps.println al ps.println (String) al posto del ps.println (Object). Questo potrebbe spiegare un tale problema, ma non ho idea se questo possibile.
Le eventuali consigli benvenuti, vi ringrazio in anticipo
EDIT: mi è stato chiesto piena traccia dello stack così qui è:
java.lang.ClassCastException: com.mycompany.util.ErrorObject incompatible with java.lang.String
at com.mycompany.util.FileUtils.writeFile(FileUtils.java:91)
at com.mycompany.util.FileUtils.writeFile(FileUtils.java:50)
at com.mycompany.itools.task.DBCompareInits.doDBTask(DBCompareInits.java:959)
at com.mycompany.itools.task.DBTask.doTask(DBTask.java:115)
at com.mycompany.itools.task.TaskGroup.startGroup(TaskGroup.java:115)
at com.mycompany.runner.Runner.main(Runner.java:209)
EDIT 2: javap -c
65: invokeinterface #20, 1; //InterfaceMethod java/util/List.size:()I
70: if_icmpge 92
73: aload 4
75: aload_1
76: iload 5
78: invokeinterface #21, 2; //InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
83: invokevirtual #31; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
86: iinc 5, 1
89: goto 62
92: aload 4
94: invokevirtual #32; //Method java/io/PrintStream.flush:()V
97: aload 4
99: invokevirtual #33; //Method java/io/PrintStream.close:()V
102: aload_3
103: invokevirtual #28; //Method java/io/FileOutputStream.close:()V
Soluzione
Mi chiedevo se il Just in Time compilatore potrebbe "filo" la ps.println al ps.println (String) al posto del ps.println (Object). Questo potrebbe spiegare un tale problema, ma non ho idea se questo possibile.
Non è possibile. O almeno non meno che ci sia un compilatore bytecode o compilatore JIT bug. E si dovrebbe dare la colpa solo bug del compilatore se avete la prova inconfutabile che sia così.
Tuttavia, la prima cosa che vorrei verificare è che il codice viene eseguito è stato davvero compilato dal codice sorgente che si sta guardando. Un modo per confermare questo sarebbe ricompilare dalla fonte, e quindi confrontare i risultati dell'esecuzione javap
sulle rispettive copie della classe. Guardando i bytecode vi dirà anche che il sovraccarico di println
compilatore bytecode sta dicendo da usare.
Modifica - l'uscita javap
mostra chiaramente che tale versione del bytecode dovrebbe chiamare println(Object)
, e non c'è nessun codice operativo checkcast
in vista. Un bug compilatore JIT che chiama il metodo sbagliato e inserisce spontaneamente codice per fare un classcast suona sempre più plausibile.
Altri suggerimenti
Dichiarare il metodo toString () con la conversione in stringa all'interno della classe ErrorObject e aggiungere + "" per println () chiamata. Come pintln (errorObjList + "");