Java no hace nada con desbordamiento de enteros para los tipos primitivos int o long e ignora el desbordamiento con enteros positivos y negativos.
Esta respuesta describe primero el desbordamiento de enteros, da un ejemplo de cómo puede suceder, incluso con valores intermedios en la evaluación de expresiones, y luego proporciona enlaces a recursos que proporcionan técnicas detalladas para prevenir y detectar el desbordamiento de enteros.
La aritmética entera y las expresiones que resultan en un desbordamiento inesperado o no detectado son un error de programación común. El desbordamiento de enteros inesperado o no detectado también es un problema de seguridad explotable bien conocido, especialmente porque afecta a los objetos de matriz, pila y lista.
El desbordamiento puede ocurrir en una dirección positiva o negativa donde el valor positivo o negativo estaría más allá de los valores máximos o mínimos para el tipo primitivo en cuestión. El desbordamiento puede ocurrir en un valor intermedio durante la evaluación de la expresión u operación y afectar el resultado de una expresión u operación donde se esperaría que el valor final esté dentro del rango.
A veces, el desbordamiento negativo se denomina erróneamente desbordamiento. Underflow es lo que sucede cuando un valor estaría más cerca de cero de lo que permite la representación. El subflujo se produce en aritmética de enteros y se espera. El desbordamiento de enteros ocurre cuando una evaluación de enteros estaría entre -1 y 0 o 0 y 1. Lo que sería un resultado fraccionario se trunca a 0. Esto es normal y esperado con aritmética de enteros y no se considera un error. Sin embargo, puede provocar que el código arroje una excepción. Un ejemplo es una excepción "ArithmeticException: / by zero" si el resultado del desbordamiento de enteros se usa como divisor en una expresión.
Considere el siguiente código:
int bigValue = Integer.MAX_VALUE;
int x = bigValue * 2 / 5;
int y = bigValue / x;
lo que da como resultado que a x se le asigne 0 y la evaluación posterior de bigValue / x arroja una excepción, "ArithmeticException: / by zero" (es decir, dividir por cero), en lugar de y se le asigna el valor 2.
El resultado esperado para x sería 858,993,458, que es menor que el valor int máximo de 2,147,483,647. Sin embargo, el resultado intermedio de evaluar Integer.MAX_Value * 2, sería 4,294,967,294, que excede el valor int máximo y es -2 de acuerdo con las representaciones enteras del complemento 2s. La evaluación posterior de -2 / 5 evalúa a 0, que se asigna a x.
Reorganizando la expresión para calcular x a una expresión que, cuando se evalúa, divide antes de multiplicar el siguiente código:
int bigValue = Integer.MAX_VALUE;
int x = bigValue / 5 * 2;
int y = bigValue / x;
da como resultado que x se asigne 858,993,458 e y se asigne 2, lo cual se espera.
El resultado intermedio de bigValue / 5 es 429,496,729 que no excede el valor máximo para un int. La evaluación posterior de 429,496,729 * 2 no excede el valor máximo para un int y el resultado esperado se asigna a x. La evaluación para y luego no se divide por cero. Las evaluaciones para x e y funcionan como se esperaba.
Los valores enteros de Java se almacenan como y se comportan de acuerdo con las representaciones enteras con signo del complemento 2s. Cuando un valor resultante sería mayor o menor que los valores enteros máximos o mínimos, en su lugar se obtiene un valor entero complementario de 2. En situaciones no diseñadas expresamente para utilizar el comportamiento del complemento 2s, que es la aritmética de enteros más común, el valor del complemento 2s resultante causará una lógica de programación o un error de cálculo como se mostró en el ejemplo anterior. Un excelente artículo de Wikipedia describe los enteros binarios complementarios 2s aquí: complemento de dos - Wikipedia
Existen técnicas para evitar el desbordamiento entero involuntario. Las Techinques pueden clasificarse según el uso de pruebas de condición previa, transmisión y BigInteger.
La prueba previa a la condición comprende examinar los valores que entran en una operación o expresión aritmética para garantizar que no se produzca un desbordamiento con esos valores. La programación y el diseño deberán crear pruebas que garanticen que los valores de entrada no causen desbordamiento y luego determinar qué hacer si se producen valores de entrada que causen desbordamiento.
La conversión ascendente comprende el uso de un tipo primitivo más grande para realizar la operación o expresión aritmética y luego determinar si el valor resultante está más allá de los valores máximos o mínimos para un número entero. Incluso con la conversión ascendente, aún es posible que el valor o algún valor intermedio en una operación o expresión supere los valores máximos o mínimos para el tipo de conversión ascendente y provoque un desbordamiento, que tampoco se detectará y causará resultados inesperados y no deseados. A través del análisis o las condiciones previas, puede ser posible evitar el desbordamiento con la transmisión cuando la prevención sin transmisión no es posible o práctica. Si los enteros en cuestión ya son tipos primitivos largos, entonces la conversión ascendente no es posible con tipos primitivos en Java.
La técnica BigInteger comprende el uso de BigInteger para la operación o expresión aritmética utilizando métodos de biblioteca que usan BigInteger. BigInteger no se desborda. Utilizará toda la memoria disponible, si es necesario. Sus métodos aritméticos son normalmente solo un poco menos eficientes que las operaciones de enteros. Todavía es posible que un resultado usando BigInteger pueda estar más allá de los valores máximos o mínimos para un entero, sin embargo, no se producirá un desbordamiento en la aritmética que conduce al resultado. La programación y el diseño aún deberán determinar qué hacer si un resultado de BigInteger está más allá de los valores máximos o mínimos para el tipo de resultado primitivo deseado, por ejemplo, int o long.
El programa CERT del Instituto de Ingeniería de Software Carnegie Mellon y Oracle han creado un conjunto de estándares para la programación segura de Java. Las normas incluyen técnicas para prevenir y detectar el desbordamiento de enteros. El estándar se publica como un recurso en línea de libre acceso aquí: El estándar de codificación segura Oracle CERT para Java
La sección del estándar que describe y contiene ejemplos prácticos de técnicas de codificación para prevenir o detectar el desbordamiento de enteros está aquí: NUM00-J. Detectar o prevenir el desbordamiento de enteros
También están disponibles el formulario de libro y el formulario PDF de CERT Oracle Secure Coding Standard para Java.