ClassCastException causé par bogue dans Just In Time?
-
19-09-2019 - |
Question
Compte tenu de ce morceau de code:
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();
}
(s'il vous plaît pas de conseils sur la façon de fermer les flux en toute sécurité, c'est le code existant et la nouvelle version utilise try / finally)
Je reçois un ClassCastException au "ps.println (BUFFER.GET (i))"
Cette méthode est appelée à plusieurs reprises (disons 5 fois) avec une liste uniquement rempli de chaînes puis, il est appelé avec une liste remplie de chaîne et un autre objet (disons ErrorObject) Au point où nous atteignons le 1er ErrorObject, nous obtenons le ClassCastException.
com.mycompany.ErrorObject incompatible with java.lang.String
Ce problème se produit dans un environnement de production, mais ne peut être reproduit dans un environnement Dev: Prod: = IBM jvm J9 VM 2.4 J2RE 1.6.0 IBM AIX 2.4 J9 ppc-32 jvmap3260-20081105_25433 (JIT activé, activé AOT) Dev: Windows XP, 1.6.0_16 JDK
Y at-il raison de ce code pourrait échouer?
Il a été patché récemment, je crains que l'équipe de production n'a pas correctement mise à jour le pot, mais mon patron déjà vérifié que le patch a été appliqué correclty ...
Je me demandais si le Juste au compilateur JIT pourrait « fil » le ps.println au ps.println (String) au lieu de l'ps.println (Object). Cela pourrait expliquer un tel problème, mais je ne sais pas si cela est possible.
Les conseils bienvenue, je vous remercie à l'avance
EDIT: on m'a demandé trace complète de la pile si elle est ici:
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
La solution
Je me demandais si le Juste au compilateur JIT pourrait « fil » le ps.println au ps.println (String) au lieu de l'ps.println (Object). Cela pourrait expliquer un tel problème, mais je ne sais pas si cela est possible.
Il est impossible. Ou du moins pas moins qu'il y ait un compilateur bytecode ou JIT bug du compilateur. Et vous ne devriez blâmer les bugs du compilateur si vous avez des preuves irréfutables que tel est le cas.
Cependant, la première chose que je voudrais vérifier est que le code en cours d'exécution a été vraiment compilé à partir du code source que vous regardez. Une façon de confirmer que ce serait recompiler de la source, puis de comparer les résultats de l'exécution javap
sur les copies respectives de la classe. En regardant le bytecode également vous dire que la surcharge de println
le compilateur bytecode dit à utiliser.
EDIT - la sortie de javap
montre clairement que cette version du bytecode doit appeler println(Object)
, et il n'y a pas checkcast
opcode en vue. Un bug du compilateur JIT qui appelle la mauvaise méthode et insère spontanément code pour faire un classcast sonne de plus en plus invraisemblables.
Autres conseils
Déclarer toString () avec la conversion en chaîne à l'intérieur de la classe ErrorObject et ajouter + « » à l'appel println (). Comme pintln (errorObjList + "");