IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Java Discussion :

Modification des valeurs d'un double lors de l'appel d'une méthode


Sujet :

Java

  1. #1
    Candidat au Club
    Inscrit en
    Septembre 2007
    Messages
    5
    Détails du profil
    Informations forums :
    Inscription : Septembre 2007
    Messages : 5
    Points : 2
    Points
    2
    Par défaut Modification des valeurs d'un double lors de l'appel d'une méthode
    Hello,

    Je travaille sur une API de génération de chart graphique (bar, line, pie etc)
    et nous avons détecté un bug bien bizarre sous plateforme AIX

    Contexte :
    -Machine AIX, avec jvm IBM 1.5 (1.4 c'est pareil)
    -Tomcat avec des webapps qui utilisent notre API
    -ligne de commande java utilisée :
    java -Djava.awt.headless=true -Xmx512m -XX:MaxPermSize=256
    (apperement le MaxPermSize n'est pas prise en compte sous jvm IBM)
    -Ce bug n'a été reproduit QUE sur cette plateforme avec SEULEMENT une JVM IBM (pas de jvm fourni par Sun pour cete plate forme)

    Bug :
    Après une bonne centaine de génération de chart de type Pie (des camemberts), les nouveaux pie sont mal dessinés. J'ai mis énormément de temps a détecter que, c'est une variable de type double qui change de valeur lors de l'appel d'une méthode en particulier....

    code appelant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    sectors[i].setPos(cx - extraXDepth, cy + extraYDepth, rx, ry, rx2, ry2,
    util.mod2pi(lastAngle + initialAngle), util.mod2pi(currentAngle + initialAngle), 
    xDepth + extraXDepth, yDepth + extraYDepth, z, (null != depths) && (0 < depths.length));
    Méthode appelée :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void setPos(int cx, int cy, int rx, int ry, int rx2, int ry2, double sAngle, double eAngle, int xDepth, int yDepth, double zAngle, boolean multiDepthMode)
    A noté que c'est toujours le second double qui foire, jamais le premier.
    J'ai rajouté des logs avant l'appel de la méthode et dans la méthode appelée
    voila ce que ca donne :
    127 PieChart before setPos 5.410963497592858
    127 PieChart in setPos 1.265E-321


    Remarques :
    -j'ai identifié 3 méthodes qui bug de cette maniere
    -la nouvelle valeur dans la méthode appelée est TOUJOURS la même dans l'instance de la jvm quand le bug apparrait (il faut redémarrer TOUTE la plateforme pour que le bug ne se reproduise plus...), donc ce n'est pas lié a une instance en particulier d'un objet
    -le tout est monothreadé (en tout cas dans la webapps qui appelle notre API)
    -Il y a plusieurs facon de 'résoudre' ce bug :
    ° changer la signature de la méthode et mettre les double en début de méthode.
    ° enlever les caluls fait 'pendant' l'appel de la méthode, c'est a dire que dans le code appelant, les appels a util.mod2pi, les additions... sont réalisés avant l'appel de la méthode et stockés dans des variables temporaires.



    On a écrit une classe de test unitaire DoubleTest.java pour esayer de reproduire le bug, cette classe génère des double et int random et effectue en boucle des appels a des méthodes avec diverses paramètres et des calculs pendant l'appel de la méthode, si on lance cette classe 'seule' (java -cp . DoubleTest) pendant une heure, tout fonctionne correctement.
    Par contre j'ai inclu un appel a cette méthode a chaque génération de pie, les valeurs changent assez vite pour un paramètre double.


    Je sais que ca peut paraitre assez léger pour bien comprendre, néanmoins je cherche pas spécialement a résoudre entierement le bug, mais plutot a savoir si un tel comportement aurait déja été identifié, et si des ténors javaistes auraient une idée sur le pourquoi du comment

    Si vous voulez d'autres infos n'éhésitez pas.

    Merci

  2. #2
    Membre expert

    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2004
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 2 301
    Points : 3 675
    Points
    3 675
    Par défaut
    J'ai lu rapidement, mais il y a un truc que je ne comprend pas: c'est la valeur d'un paramètre qui est modifiée par la méthode? Genre

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    double d = 1.;
    callTheMethodThatBug(d);
    System.out.println(d==1.); // Ecrit false ?
    Est-ce que c'est bien cela?
    "Le plug gros problème des citations trouvées sur internet, c'est qu'on ne peut jamais garantir leur authenticité"

    Confucius, 448 av. J-C

  3. #3
    Candidat au Club
    Inscrit en
    Septembre 2007
    Messages
    5
    Détails du profil
    Informations forums :
    Inscription : Septembre 2007
    Messages : 5
    Points : 2
    Points
    2
    Par défaut
    Oui c'est ca
    pour faire simple

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Class A {
    double d = 25.24;
        main {
        new ClassB().setPos(d);
        }
    }
     
    Class B {
       setPos(double d) {
       System.out.println(d);   
       }
    }
    le print affichera un nombre extraordinairement grand ou petit (du genre 2.0xxxE-250)

  4. #4
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Salut,


    Tu aurais un exemple de code qui reproduirait le problème ?

    a++

  5. #5
    Membre expert

    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2004
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 2 301
    Points : 3 675
    Points
    3 675
    Par défaut
    Citation Envoyé par aurel56 Voir le message
    Oui c'est ca



    Bah moi je serais tenté de dire que c'est impossible (mais bon)...

    Elle est en version finale cette JVM? parce que bon, c'est un bug tellement énorme que ça m'étonnerait qu'il tienne jusqu'à une release...

    D'autant que les types primitifs (int, double, boolean, etc.) sont passés par valeurs, donc sur la pile, et qu'une méthode ne peut en aucun cas modifier un double en dehors d'elle-même...

    On dirait justement que le bug est au niveau de la gestion de la pile et des passages de paramètres...

    Tu n'as trouvé aucune description de bug sur le site IBM?
    "Le plug gros problème des citations trouvées sur internet, c'est qu'on ne peut jamais garantir leur authenticité"

    Confucius, 448 av. J-C

  6. #6
    Candidat au Club
    Inscrit en
    Septembre 2007
    Messages
    5
    Détails du profil
    Informations forums :
    Inscription : Septembre 2007
    Messages : 5
    Points : 2
    Points
    2
    Par défaut
    adiGuba :
    J'arrive bien a reproduire le bug avece cette clase de test unitaire, mais c'est quand on la branche dans notre API, en dehors, tout marche tres bien :
    Je pense pas que tu arriveras a la reproduire juste en lancant la classe
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
     
    public class DoubleTest
    {
     
     
        private double[] check = new double[6];
     
        public DoubleTest()
        {
     
        }
     
     
        private boolean mixedcheckedRadians(int i0, int i1, double d0, double d1, int i2, int i3, double d2, double d3, double d4, int i4, int i5, double d5)
        {
            if (!(d0 == Math.toRadians(check[0])))
            {
                System.out.println("mixedcheckedRadians d0 double mismatch:" + d0 + " expected:" + Math.toRadians(check[0]) + ")");
                return false;
            }
     
            if (!(d1 == Math.toRadians(check[1])))
            {
                System.out.println("mixedcheckedRadians d1 double mismatch:" + d1 + " expected:" + Math.toRadians(check[1]) + ")");
                return false;
            }
     
            if (!(d2 == Math.toRadians(check[2])))
            {
                System.out.println("mixedcheckedRadians d2 double mismatch:" + d2 + " expected:" + Math.toRadians(check[2]) + ")");
                return false;
            }
     
            if (!(d3 == Math.toRadians(check[3])))
            {
                System.out.println("mixedcheckedRadians d3 double mismatch:" + d3 + " expected:" + Math.toRadians(check[3]) + ")");
                return false;
            }
     
            if (!(d4 == Math.toRadians(check[4])))
            {
                System.out.println("mixedcheckedRadians d4 double mismatch:" + d4 + " expected:" + Math.toRadians(check[4]) + ")");
                return false;
            }        
     
            if (!(d5 == Math.toRadians(check[5])))
            {
                System.out.println("mixedcheckedRadians d5 double mismatch:" + d5 + " expected:" + Math.toRadians(check[5]) + ")");
                return false;
            }        
     
            return true;
        }
     
        public void test(long loops)
        {
            System.out.println(". ");
     
            long i = 0; 
            for (; i < loops; i++)
            {
                double d0 = Math.random() * 1000;
                double d1 = Math.random() * 1000;
                double d2 = Math.random() * 1000;
                double d3 = Math.random() * 1000;
                double d4 = Math.random() * 1000;
                double d5 = Math.random() * 1000;
     
                check[0] = d0;
                check[1] = d1;
                check[2] = d2;
                check[3] = d3;
                check[4] = d4;
                check[5] = d5;
     
                int i0 = (int) (Math.random() * 1000);
                int i1 = (int) (Math.random() * 1000);
                int i2 = (int) (Math.random() * 1000);
                int i3 = (int) (Math.random() * 1000);
                int i4 = (int) (Math.random() * 1000);
                int i5 = (int) (Math.random() * 1000);
     
     
                if (!mixedcheckedRadians(
                        (i0 > 300) ? -i0 : i0 + 15, 
                        (i1 < 800 ) ?  i1 + 1000 : i1, 
                        Math.toRadians(d0),
                        Math.toRadians(d1),
                        (i2 == 0) ? -300 : -2, 
                        (i3 + 60 > 80 ) ? -i3 - 30 : i3 + 500,
                        Math.toRadians(d2),
                        Math.toRadians(d3),
                        Math.toRadians(d4),
                        i4, 
                        (i5 > i4) ? (i5 - i4) : (i5 + i4),
                        Math.toRadians(d5)))
                    break;
     
     
            }        
     
     
        }
     
        /**
         * @param args
         */
        public static void main(String[] args)
        {
            long outerLoop = 50;
            long innerLoop = 10000;
     
            if (args.length == 2)
            {
                outerLoop = Long.parseLong(args[0]);
                innerLoop = Long.parseLong(args[1]);
            }
     
            System.out.println("starting DoubleTest with outer loop:" + outerLoop + " and inner loop:" + innerLoop);
            System.out.println("starting at "+new Date(System.currentTimeMillis()).toGMTString());
            for (int i = 0; i < outerLoop; i++)
            {
                DoubleTest testClass = new DoubleTest();
                testClass.test(innerLoop, 1);
            }
            System.out.println("");
            System.out.println("ended DoubleTest");
            System.out.println("ending at "+new Date(System.currentTimeMillis()).toGMTString());
        }
     
    }

    Pill_S :
    On a essayé avec plusieurs JVM (1.4 comme 1.5), différentes build (toutes finales), le bug se reproduit facilement, mais c'est dans un contexte vraiment particulier (tomcat, webapps, notre api branché, plein d'autre api dans le classpath... ). Donc il est possible que ce soit un bug vraiment pas facile a reproduire (et bien sur, je tombe dessus )

    Et oui c'est incroyable...
    Rien de trouvé d'interessant sur le site d'IBM.
    J'ai essayé en désactivant la jit, idem
    On a pensé a un probleme de stack, mais AUCUNE exception n'arrive...
    Bref, je sais pu trop ou regardé

Discussions similaires

  1. Réponses: 7
    Dernier message: 03/02/2012, 17h15
  2. problème lors de l'appel d'une méthode
    Par sfaxian dans le forum VB.NET
    Réponses: 9
    Dernier message: 10/07/2009, 14h39
  3. Erreur lors de l'appel d'une méthode Zend Helper
    Par donbrico dans le forum Zend Framework
    Réponses: 4
    Dernier message: 16/04/2008, 15h52
  4. [forward] Erreur lors de l'appel d'une méthode
    Par GLDavid dans le forum Servlets/JSP
    Réponses: 2
    Dernier message: 03/07/2007, 17h10
  5. POO Trap lors de l'appel d'une méthode
    Par QAYS dans le forum Delphi
    Réponses: 3
    Dernier message: 05/06/2007, 21h22

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo