Developpez.com

Le Club des Développeurs et IT Pro

Le bogue des nombres à virgule flottante refait surface en Java

Il plonge le compilateur et les programmes dans des boucles infinies

Le 2011-02-08 13:23:03, par Idelways, Expert éminent sénior
Mise à jour du 08/02/2011

Quelque temps après sa correction sur PHP, le bogue étrange des nombres à virgule flottante refait surface sur un langage tout aussi populaire : Java.

Ce bogue provoquait sur PHP avant sa correction le crash du système par le passage d'un simple paramètre dans l'URL, pour peu que le script convertisse en nombres ou utilise ces variables dans des opérations arithmétiques (pour plus de détails, lire ci-devant)

Sur Java, un bogue similaire plongerait les programmes à l'exécution (ou leur compilateur) dans des boucles infinies d'après Exploring Binary, le site où ont été mis en lumière les deux bogues.

Le nombre en question, le désormais célèbre 2.2250738585072012e-308 et ses différentes représentations sont supposés être convertie en 0x1p-1022, qui correspond à la constante DBL_MIN.
Au lieu de cela, Java se retrouve coincé, oscillant sans arrêt entre les valeurs 0x1p-1022 et 0x0.fffffffffffffp-1022, le plus grand nombre dénormalisé à double précision et à virgule flottante.

Le bogue serait provoqué par la boucle de correction de la classe FloatingDecimal, chargée de trouver la meilleure approximation, qui la trouve mais la remplace et la retrouve infiniment...

Le bogue a été reporté à Oracle depuis plusieurs semaines, son rapport a récemment été assigné pour analyse interne non accessible sur Sun Developer Network (SDN).

Pour reproduire ce bogue à l'exécution des programmes, compilez et exécutez ce programme

Code :
1
2
3
4
5
6
7
class runhang {
public static void main(String[] args) {
  System.out.println("Test:");
  double d = Double.parseDouble("2.2250738585072012e-308");
  System.out.println("Value: " + d);
 }
}

Pour provoquer une boucle infinie au niveau du compilateur, il suffit de tenter de compiler cette classe :
Code :
1
2
3
4
5
6
class compilehang {
public static void main(String[] args) {
  double d = 2.2250738585072012e-308;
  System.out.println("Value: " + d);
 }
}


Source : Exploring Binary

Et vous ?

Arrivez-vous à reproduire ce bug ?
Sur quelle plateforme, architecture et version de JRE/JDK ?
  Discussion forum
64 commentaires
  • YannPeniguel
    Membre éprouvé
    Envoyé par ztor1
    Question idiote ?

    Je peux ?

    Qui utilise un chiffre pareil ? 2.2250738585072011e-308

    Cela me fait penser au bug du pentium I à sa sortie.

    Les exemples cités java ou php ... On utilise vraiment cela ?

    Toute personne malveillante connaissant ce bug et souhaitant dégommer ton application par un moyen, exposé publiquement, de lui fournir cette valeur en entrée. Mettons par exemple dans les appels AJAX utilisant des JSP, ou dans les parametres d'url pour tes servlets Java...
  • Cryde
    Membre du Club
    Comme quoi, les détracteurs du PHP auront vite compris qu'il n'y a pas que ce langage qui posait problème avec ça ^^
  • Rom_1
    Membre régulier
    Envoyé par Flaburgan

    Enfin, si deni de service est pris dans le seul "le serveur ne peut plus répondre car occupé à autre chose", ok, je comprends.
    Une attaque par déni de service est une attaque visant à rendre un service inutilisable.

    Si ca marche avec une seule requête, l'attaque n'en est que plus efficace.
    Mais normalement, le serveur web devrait utiliser un thread par requête (donc une requête ne bloque au maximum qu'un cœur et pas le service entier) et tuer le thread après un certain temps d'exécution.

    Enfin c'est quand même sacrément efficace.

    EDIT : vu les explications de la personne qui a découvert le bug, le problème vient du fait que la FPU des processeurs x86 utilise une précision étendue (80 bits) dans tous les cas, et ne sait pas calculer en double précision (64 bits). Donc ca viendrait plus de la plate-forme que du langage.

    Et donc, ce ne serait pas étonnant que d'autres langages soient touchés, par exemple .net ou python...
  • stealth35
    Expert éminent sénior
    Envoyé par camus3
    C'est à mon avis un moindre problème dans java ou les données sont strictement typées. Mais je peux me tromper
    non c'est pareil.
  • Derek Corgan
    Membre chevronné
    Effectivement, Eclipse plante lamentablement à l'exécution (Eclipse 3.4, JKD1.6_20 + Windows XP).

    Avant, la probabilité de survenance de ce bug était quasi nulle.

    Maintenant que cela est connu il risque d'apparaitre dans des flux de données, soit pour faire une petite blague à un collègue ou pour faire chier
  • nidget
    Membre du Club
    Je confirme ce bug sur JDK 1.6.0_20
  • YannPeniguel
    Membre éprouvé
    Envoyé par centsoucis
    Bonjour, Pourquoi ne pas être rationnelle? Ce n'est pas l'étendu du nombre qui permet ma précision. Un nombre calculé peut être irationnel. Le stockage d'une valeur même flotante peut être relative dans la mesure de son exploitation. Alors pourquoi (mis à part certains domaine bien spécifique) approcher au plus juste une valeur irrationnelle? Tant que ce bug n'e'st pas résolu, il est toujours possible d'avoir une précision qui nous dépasse sans remédier au bug.
    La question n'est pas que ce soit bloquant en terme d'usage, mais que cela permette de provoquer le plantage d'une application, potentiellement une application JEE qui impactera des milliers d'utilisateurs (ERP, CRM...)
  • Lorantus
    Membre éclairé
    Ce patch est interssant, car il est en Java. Un peu de rétro-engenering pour voir "comment cela se passe".
    Je sais, c'est pas bien
  • igor24
    Membre régulier
    Eclipse a planté rien qu'en collant le 2nd bout de code ..., normal il compile à la volée
  • ztor1
    Membre averti
    Question idiote ?

    Je peux ?

    Qui utilise un chiffre pareil ? 2.2250738585072011e-308

    Cela me fait penser au bug du pentium I à sa sortie.

    Les exemples cités java ou php ... On utilise vraiment cela ?