Java ничего не делает с целочисленным переполнением ни для int, ни для длинных примитивных типов, и игнорирует переполнение положительными и отрицательными целыми числами.
В этом ответе сначала описывается целочисленное переполнение, дается пример того, как это может произойти даже с промежуточными значениями при вычислении выражений, а затем даются ссылки на ресурсы, которые предоставляют подробные методы предотвращения и обнаружения целочисленного переполнения.
Целочисленная арифметика и выражения, приводящие к неожиданному или необнаруженному переполнению, являются распространенной ошибкой программирования. Неожиданное или необнаруженное целочисленное переполнение также является хорошо известной уязвимостью, которая может использоваться, особенно когда она затрагивает объекты массива, стека и списка.
Переполнение может происходить в положительном или отрицательном направлении, где положительное или отрицательное значение будет выше максимального или минимального значения для рассматриваемого типа примитива. Переполнение может произойти в промежуточном значении во время выражения или операции и повлиять на результат выражения или операции, где ожидается, что окончательное значение будет в пределах диапазона.
Иногда отрицательное переполнение ошибочно называют недостаточным. Недостаток - это то, что происходит, когда значение будет ближе к нулю, чем позволяет представление. Недостаток происходит в целочисленной арифметике и ожидается. Потеря целочисленного значения происходит, когда целочисленное вычисление будет между -1 и 0 или 0 и 1. То, что будет дробным результатом, усекается до 0. Это нормально и ожидается с целочисленной арифметикой и не считается ошибкой. Однако это может привести к исключению кода. Одним из примеров является исключение «ArithmeticException: / by zero», если результат целочисленного занижения используется в качестве делителя в выражении.
Рассмотрим следующий код:
int bigValue = Integer.MAX_VALUE;
int x = bigValue * 2 / 5;
int y = bigValue / x;
что приводит к тому, что x присваивается 0, а последующая оценка bigValue / x вызывает исключение «ArithmeticException: / by zero» (т. е. делится на ноль) вместо y, которому присваивается значение 2.
Ожидаемый результат для x будет 858,993,458, что меньше, чем максимальное значение int 2,147,483,647. Однако промежуточный результат от оценки Integer.MAX_Value * 2 будет равен 4 294 967 294, что превышает максимальное значение int и равно -2 в соответствии с представлениями целых чисел дополнения 2s. Последующая оценка -2 / 5 оценивается в 0, что присваивается х.
Переставляем выражение для вычисления x в выражение, которое при вычислении делит перед умножением следующий код:
int bigValue = Integer.MAX_VALUE;
int x = bigValue / 5 * 2;
int y = bigValue / x;
в результате х присваивается 858,993,458, а у назначается 2, что ожидается.
Промежуточный результат от bigValue / 5 составляет 429 496 729, что не превышает максимальное значение для типа int. Последующая оценка 429 496 729 * 2 не превышает максимальное значение для int, и ожидаемый результат присваивается x. Оценка для y тогда не делится на ноль. Оценки для x и y работают как ожидалось.
Целочисленные значения Java хранятся как и ведут себя в соответствии с дополнением 2s со знаком целочисленных представлений. Когда результирующее значение будет больше или меньше, чем максимальное или минимальное целочисленные значения, вместо этого получается целочисленное значение дополнения 2. В ситуациях, специально не предназначенных для использования поведения дополнения 2s, которое является наиболее обычными целочисленными арифметическими ситуациями, результирующее значение дополнения 2s вызовет программную логику или ошибку вычисления, как было показано в примере выше. Отличная статья в Википедии описывает двоичные числа с комплиментами 2s здесь: Дополнение к двум - Википедия
Существуют методы, позволяющие избежать непреднамеренного целочисленного переполнения. Techinques могут быть классифицированы как использование предварительного тестирования, апкастинга и BigInteger.
Предварительное тестирование включает проверку значений, входящих в арифметическую операцию или выражение, чтобы убедиться, что переполнение этими значениями не произойдет. Программирование и проектирование должны будут создать тестирование, которое обеспечит, чтобы входные значения не вызывали переполнения, а затем определяло, что делать, если входные значения происходят, что приведет к переполнению.
Upcasting включает использование большего типа примитива для выполнения арифметической операции или выражения, а затем определение, превышает ли результирующее значение максимальное или минимальное значения для целого числа. Даже при использовании восходящего вещания все еще возможно, что значение или некоторое промежуточное значение в операции или выражении будут превышать максимальные или минимальные значения для типа восходящего вещания и вызывают переполнение, которое также не будет обнаружено и приведет к неожиданным и нежелательным результатам. Посредством анализа или предварительных условий может быть возможно предотвратить переполнение с помощью апкастинга, когда предотвращение без апскейтинга невозможно или практически невозможно. Если рассматриваемые целые числа уже являются длинными примитивными типами, то в Java примитивные типы невозможны.
Техника BigInteger включает использование BigInteger для арифметической операции или выражения с использованием библиотечных методов, которые используют BigInteger. BigInteger не переполняется. Он будет использовать всю доступную память, если это необходимо. Его арифметические методы обычно лишь немного менее эффективны, чем целочисленные операции. Все еще возможно, что результат, использующий BigInteger, может быть выше максимального или минимального значения для целого числа, однако переполнение не будет происходить в арифметике, приводящей к результату. Программирование и проектирование все еще должны определить, что делать, если результат BigInteger превышает максимальные или минимальные значения для желаемого примитивного типа результата, например, int или long.
Программа CERT Института разработки программного обеспечения Карнеги-Меллона и Oracle создали набор стандартов для безопасного программирования на Java. В стандарты включены методы предотвращения и обнаружения целочисленного переполнения. Стандарт опубликован в виде свободно доступного онлайн-ресурса здесь: CERT Oracle Secure Coding Standard для Java
Раздел стандарта, который описывает и содержит практические примеры методов кодирования для предотвращения или обнаружения целочисленного переполнения, находится здесь: NUM00-J. Обнаружение или предотвращение целочисленного переполнения
Книжная форма и PDF-форма CERT Oracle Secure Coding Standard для Java также доступны.