Langage | Entier non signé | Entier signé |
---|---|---|
Ada | modulo. le module du type | raise Constraint_Error |
C/C++ | modulo puissance de deux | comportement indéfini |
C# | modulo puissance de 2 dans un contexte non vérifié ; System.OverflowException est soulevée dans le contexte vérifié |
|
Java | N/A | modulo puissance de deux |
JavaScript | tous les nombres sont en virgule flottante à double-précision en virgule flottante sauf le nouveau BigInt | |
MATLAB | Les entiers construits saturent. Fixe-point integers configurable pour envelopper ou saturer | |
Python 2 | N/A | convertir en type long. (bigint) |
Seed7 | N/A | raise OVERFLOW_ERROR |
Scheme | N/A | converti en bigNum |
Simulink | configurable pour envelopper ou saturer | |
Smalltalk | N/A | convertir en LargeInteger |
Swift | Cause une erreur à moins d’utiliser des opérateurs spéciaux de débordement. |
DétectionEdit
L’implémentation de la détection de débordement en cours d’exécution UBSan
est disponible pour les compilateurs C.
En Java 8, il existe des méthodes surchargées, par exemple comme Math.addExact(int, int)
, qui lanceront ArithmeticException
en cas de débordement.
L’équipe d’intervention d’urgence en informatique (CERT) a développé le modèle d’entier As-if Infinitely Ranged (AIR), un mécanisme largement automatisé pour éliminer le débordement et la troncature des entiers en C/C++ en utilisant la gestion des erreurs d’exécution.
EvitementEdit
En allouant des variables avec des types de données qui sont assez grands pour contenir toutes les valeurs qui peuvent éventuellement être calculées et stockées en eux, il est toujours possible d’éviter le débordement. Même lorsque l’espace disponible ou les types de données fixes fournis par un langage ou un environnement de programmation sont trop limités pour permettre l’allocation défensive de variables de taille généreuse, en ordonnant soigneusement les opérations et en vérifiant les opérandes à l’avance, il est souvent possible de s’assurer a priori que le résultat ne sera jamais plus grand que ce qui peut être stocké. Les outils d’analyse statique, la vérification formelle et les techniques de conception par contrat peuvent être utilisés pour assurer avec plus de confiance et de robustesse qu’un débordement ne peut pas résulter accidentellement.
HandlingEdit
S’il est prévu qu’un débordement puisse se produire, alors des tests peuvent être insérés dans le programme pour détecter quand il se produit, ou est sur le point de se produire, et faire d’autres traitements pour l’atténuer. Par exemple, si un résultat important calculé à partir de l’entrée de l’utilisateur déborde, le programme peut s’arrêter, rejeter l’entrée, et peut-être demander à l’utilisateur une autre entrée, plutôt que de poursuivre avec l’entrée débordante invalide et probablement un mauvais fonctionnement en conséquence. Ce processus complet peut être automatisé : il est possible de synthétiser automatiquement un gestionnaire pour un débordement d’entier, où le gestionnaire est par exemple une sortie propre.
Les CPU ont généralement un moyen de détecter cela pour supporter l’addition de nombres plus grands que la taille de leur registre, typiquement en utilisant un bit d’état ; la technique est appelée arithmétique à précision multiple.Ainsi, il est possible d’additionner deux nombres de deux octets chacun en utilisant simplement une addition d’octets par étapes : d’abord additionner les octets de poids faible puis additionner les octets de poids fort, mais s’il est nécessaire de sortir des octets de poids faible, c’est un débordement arithmétique de l’addition d’octets et il devient nécessaire de détecter et d’incrémenter la somme des octets de poids fort.
Gérer le dépassement possible d’un calcul peut parfois présenter un choix entre effectuer une vérification avant le calcul réel (pour déterminer si oui ou non le dépassement va se produire), ou après (pour considérer si oui ou non il s’est probablement produit en fonction de la valeur résultante). Il convient de faire preuve de prudence à l’égard de ce dernier choix. Tout d’abord, parce qu’il peut ne pas être une méthode de détection fiable (par exemple, une addition ne se traduit pas nécessairement par une valeur inférieure). Deuxièmement, parce que l’apparition d’un débordement peut, dans certains cas, constituer un comportement non défini. Dans le langage de programmation C, le dépassement de capacité des types d’entiers non signés entraîne un enveloppement, mais le dépassement de capacité des types d’entiers signés est un comportement non défini ; par conséquent, un compilateur C est libre de supposer que le programmeur s’est assuré que le dépassement de capacité signé ne peut pas se produire et il peut donc optimiser silencieusement toute vérification postérieure au calcul qui implique de vérifier le résultat pour le détecter sans avertir le programmeur que cela a été fait. Il est donc conseillé de toujours préférer mettre en place des vérifications avant les calculs et non après.
Propagation expliciteEdit
si une valeur est trop grande pour être stockée, on peut lui attribuer une valeur spéciale indiquant qu’un débordement s’est produit et faire en sorte que toutes les opérations successives renvoient cette valeur d’indicateur. De telles valeurs sont parfois appelées NaN, pour « not a number » (pas un nombre). Ceci est utile pour que le problème puisse être vérifié une fois à la fin d’un long calcul plutôt qu’après chaque étape. Ceci est souvent pris en charge dans le matériel à virgule flottante appelé FPU.
Support des langages de programmationEdit
Les langages de programmation mettent en œuvre diverses méthodes d’atténuation contre un débordement accidentel : Ada, Seed7 (et certaines variantes de langages fonctionnels), déclenchent une condition d’exception en cas de débordement, tandis que Python (depuis 2.4) convertit de manière transparente la représentation interne du nombre pour qu’elle corresponde à sa croissance, le représentant finalement sous la forme long
– dont la capacité n’est limitée que par la mémoire disponible.
Dans les langages qui supportent nativement l’arithmétique à précision arbitraire et la sécurité des types (comme Python, Smalltalk ou Common Lisp), les nombres sont promus à une taille supérieure automatiquement lorsque des débordements se produisent, ou des exceptions lancées (conditions signalées) lorsqu’une contrainte d’étendue existe. L’utilisation de ces langages peut donc être utile pour atténuer ce problème. Toutefois, dans certains de ces langages, il existe encore des situations où un dépassement de capacité peut se produire. Un exemple est l’optimisation explicite d’un chemin de code qui est considéré comme un goulot d’étranglement par le profileur. Dans le cas de Common Lisp, cela est possible en utilisant une déclaration explicite pour annoter le type d’une variable à un mot de taille machine (fixnum) et abaisser le niveau de sécurité de type à zéro pour un bloc de code particulier.
Contrairement aux anciens langages comme C, certains langages plus récents, comme Rust par exemple, fournissent des fonctionnalités intégrées qui permettent une détection facile et un choix de l’utilisateur sur la façon dont le débordement doit être géré au cas par cas. Dans Rust, alors que l’utilisation des opérateurs mathématiques de base manque naturellement d’une telle flexibilité, les utilisateurs peuvent alternativement effectuer des calculs via un ensemble de méthodes fournies par chacun des types primitifs entiers. Ces méthodes donnent aux utilisateurs plusieurs choix entre l’exécution d’une opération « vérifiée » (ou « débordement ») (qui indique si un débordement s’est produit ou non via le type de retour) ; une opération « non vérifiée » ; une opération qui effectue un enveloppement ou une opération qui effectue une saturation au niveau des limites numériques.
Arithmétique saturéeEdit
En infographie ou en traitement du signal, il est typique de travailler sur des données qui vont de 0 à 1 ou de -1 à 1. Par exemple, prenons une image en niveaux de gris où 0 représente le noir, 1 le blanc et les valeurs intermédiaires représentent des nuances de gris. Une opération que l’on peut vouloir prendre en charge consiste à éclaircir l’image en multipliant chaque pixel par une constante. L’arithmétique saturée permet de simplement multiplier aveuglément chaque pixel par cette constante sans se soucier du débordement en s’en tenant à un résultat raisonnable selon lequel tous ces pixels supérieurs à 1 (c’est-à-dire « plus clairs que blancs ») deviennent simplement blancs et toutes les valeurs « plus sombres que noires » deviennent simplement noires.