Java does not provide any indication of overflow conditions and silently wraps, which can result in incorrect computations and unanticipated outcomes.
According to the Java Language Specification, Section 4.2.2, "Integer Operations"
The built-in integer operators do not indicate overflow or underflow in any way. Integer operators can throw a
NullPointerException
if unboxing conversion of anull
reference is required. Other than that, the only integer operators that can throw an exception are the integer divide operator/
and the integer remainder operator%
, which throw anArithmeticException
if the right-hand operand is zero, and the increment and decrement operators ++ and -- which can throw anOutOfMemoryError
if boxing conversion is required and there is not sufficient memory available to perform the conversion.
The integral types in Java are byte
, short
, int
, and long
, whose values are 8-bit, 16-bit, 32-bit and 64-bit signed twoâs-complement integers, respectively, and char
, whose values are 16-bit unsigned integers representing UTF-16 code units.
According to the Java Language Specification, Section 4.2.1, "Integral Types and Values," the values of the integral types are integers in the inclusive ranges shown in the following table:
Type | Inclusive Range |
---|---|
| --128 to 127 |
| --32,768 to 32,767 |
| --2,147,483,648 to 2,147,483,647 |
| --9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 |
| |
The table below shows the integer overflow behavior of the integral operators.
Operator | Overflow |
| Operator | Overflow |
| Operator | Overflow |
| Operator | Overflow |
---|---|---|---|---|---|---|---|---|---|---|
{+} |
Wiki Markup |
---|
According to Sun's Secure Coding Guidelines \[[SCG 2007|AA. Bibliography#SCG 07]\] |
The (Java) language is type-safe, and the runtime provides automatic memory management and range-checking on arrays. These features also make Java programs immune to the stack-smashing and buffer overflow attacks possible in the C and C++ programming languages, and that has been described as the single most pernicious problem in computer security today.
While this statement is true, arithmetic operations in the Java platform require just as much caution as do the analogous operations in C and C++, because integer operations in Java can still result in overflow. Java does not provide any indication of overflow conditions and silently wraps. While integer overflows in vulnerable C and C++ programs can result in the execution of arbitrary code; in Java, wrapped values typically result in incorrect computations and unanticipated outcomes.
According to the Java Language Specification, Section 4.2.2, "Integer Operations"
The built-in integer operators do not indicate overflow or underflow in any way. Integer operators can throw a
NullPointerException
if unboxing conversion of anull
reference is required. Other than that, the only integer operators that can throw an exception are the integer divide operator/
and the integer remainder operator%
, which throw anArithmeticException
if the right-hand operand is zero, and the increment and decrement operators ++ and -- which can throw anOutOfMemoryError
if boxing conversion is required and there is not sufficient memory available to perform the conversion.
The integral types in Java are byte
, short
, int
, and long
, whose values are 8-bit, 16-bit, 32-bit and 64-bit signed twoâs-complement integers, respectively, and char
, whose values are 16-bit unsigned integers representing UTF-16 code units.
According to the Java Language Specification, Section 4.2.1, "Integral Types and Values," the values of the integral types are integers in the inclusive ranges shown in the following table:
Type | Inclusive Range |
---|---|
| â“128 to 127 |
| â“32,768 to 32,767 |
| â“2,147,483,648 to 2,147,483,647 |
| â“9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 |
| |
The table below shows the integer overflow behavior of the integral operators.
Operator | Overflow |
| Operator | Overflow |
| Operator | Overflow |
| Operator | Overflow |
---|---|---|---|---|---|---|---|---|---|---|
| yes |
| | yes |
| | no |
| | no |
| yes |
| | yes |
| | no |
| | no |
| yes |
| | yes |
| | no |
| | no |
| yes |
| | no |
| \ | no |
| | no |
| no |
| | no |
| {^} | no |
| | no |
| yes |
| | no |
| {~} | no |
| | no |
| yes |
| | no |
| | no |
| ||
| no |
| | no |
| un {+} | no |
| ||
| yes |
| | no |
| un | yes |
|
Wiki Markup |
---|
Failure to account for integer overflow has resulted in failures of real systems, for example, when implementing the {{compareTo()}} method. The meaning of the return value of the {{compareTo()}} method is defined only in terms of its sign and whether it is zero; the magnitude of the return value is irrelevant. Consequently, an apparent but incorrect optimization would be to subtract the operands and return the result. For operands of opposite signs, this can result in integer overflow, consequently violating the {{compareTo()}} contract \[[Bloch 2008, Item 12|AA. Bibliography#Bloch 08]\]. |
...
- Upcasting. Cast the inputs to the next larger primitive integer type and perform the arithmetic in the larger size. Check each intermediate result for overflow of the original smaller type, and throw an
ArithmeticException
if the range check fails. Note that the range check must be performed after each arithmetic operation; larger expressions without per-operation bounds checking may overflow the larger type. Downcast the final result to the original smaller type before assigning to the result variable. This approach cannot be used for typelong
becauselong
is already the largest primitive integer type.
BigInteger
. Convert the inputs into objects of typeBigInteger
and perform all arithmetic usingBigInteger
methods. TypeBigInteger
is the standard arbitrary-precision integer type provided by the Java standard libraries. The arithmetic operations implemented as methods of this type cannot themselves overflow; instead, they produce the numerically correct result. As a consequence, compliant code performs only a single range checkâ”just check---just before converting the final result to the original smaller type and throw anArithmeticException
if the final result is outside the range of the original smaller type.
...
Code Block | ||
---|---|---|
| ||
static final int preAddsafeAdd(int left, int right) throws ArithmeticException { if (right > 0 ? left > Integer.MAX_VALUE - right : left < Integer.MIN_VALUE - right) { throw new ArithmeticException("Integer overflow"); } return left + right; } static final int preSubtractsafeSubtract(int left, int right) throws ArithmeticException { if (right > 0 ? left < Integer.MIN_VALUE + right : left > Integer.MAX_VALUE + right) { throw new ArithmeticException("Integer overflow"); } return left - right; } static final int preMultiplysafeMultiply(int left, int right) throws ArithmeticException { if (right > 0 ? left > Integer.MAX_VALUE/right || left < Integer.MIN_VALUE/right : (right < -1 ? left > Integer.MIN_VALUE/right || left < Integer.MAX_VALUE/right : right == -1 && left == Integer.MIN_VALUE) ) { throw new ArithmeticException("Integer overflow"); } return left * right; } static final int preDividesafeDivide(int left, int right) throws ArithmeticException { if ((left == Integer.MIN_VALUE) && (right == -1)) { throw new ArithmeticException("Integer overflow"); } return left / right; } static final int preAbssafeAbs(int a) throws ArithmeticException { if (a == Integer.MIN_VALUE) { throw new ArithmeticException("Integer overflow"); } return Math.abs(a); } static final int preNegatesafeNegate(int a) throws ArithmeticException { if (a == Integer.MIN_VALUE) { throw new ArithmeticException("Integer overflow"); } return -a; } |
...
Code Block | ||
---|---|---|
| ||
public static int multAccum(int oldAcc, int newVal, int scale) {
// May result in overflow
return oldAcc + (newVal * scale);
}
|
...
This compliant solution uses the preAddsafeAdd()
and preMultiplysafeMultiply()
methods defined in the Pre-condition testing section to perform secure integral operations or throw ArithmeticException
on overflow.
Code Block | ||
---|---|---|
| ||
public static int multAccum(int oldAcc, int newVal, int scale) throws ArithmeticException { return preAddsafeAdd(oldAcc, preMultiplysafeMultiply(newVal, scale)); } |
Compliant Solution (Upcasting)
This compliant solution shows the implementation of a method for checking whether a long
value falls within the representable range of an int
using the upcasting technique. The implementations of range checks for the smaller primitive integer types are similar.
Code Block | ||
---|---|---|
| ||
public static long intRangeCheck(long value) throws ArithmeticOverflow { if ((value < Integer.MIN_VALUE) || (value > Integer.MAX_VALUE)) { throw new ArithmeticException("Integer overflow"); } return value; } public static int multAccum(int oldAcc, int newVal, int scale) throws ArithmeticException { final long res = intRangeCheck(((long) oldAcc) + intRangeCheck((long) newVal * (long) scale)); return (int) res; // safe down-cast } |
...
Code Block | ||
---|---|---|
| ||
private static final BigInteger bigMaxInt = BigInteger.valueOf(Int.MAX_VALUE);
private static final BigInteger bigMinInt = BigInteger.valueOf(Int.MIN_VALUE);
public static BigInteger intRangeCheck(BigInteger val) throws ArithmeticException {
if (val.compareTo(bigMaxInt) == 1 ||
val.compareTo(bigMinInt) == -1) {
throw new ArithmeticException("Integer overflow");
}
return val;
}
public static int multAccum(int oldAcc, int newVal, int scale) throws ArithmeticException {
BigInteger product =
BigInteger.valueOf(newVal).multiply(BigInteger.valueOf(scale));
BigInteger res = intRangeCheck(BigInteger.valueOf(oldAcc).add(product));
return res.intValue(); // safe conversion
}
|
Noncompliant Code Example (Math.abs()
)
Overflow is also possible via the java.lang.Math.abs()
function, which returns a number's absolute value.
Code Block | ||
---|---|---|
| ||
public int magnitude(int i) {
return Math.abs(i);
}
|
When Integer.MIN_VALUE
(â“2,147,483,648) is passed to Math.abs()
, the result is Integer.MIN_VALUE
, rather than the expected -Integer.MIN_VALUE
, because -Integer.MIN_VALUE
cannot be represented as an int
.
Compliant Solution (Math.abs()
)
This compliant solution uses the pre-condition testing approach to safely return the absolute value of a number.
Code Block | ||
---|---|---|
| ||
static final int preAbs(int i(int oldAcc, int newVal, int scale) throws ArithmeticException { ifBigInteger (iproduct == Integer.MIN_VALUE) { BigInteger.valueOf(newVal).multiply(BigInteger.valueOf(scale)); BigInteger res throw new ArithmeticException("Integer overflow")= intRangeCheck(BigInteger.valueOf(oldAcc).add(product)); } return Mathres.absintValue(i); } public int magnitude(int i) throws ArithmeticException { return preAbs(i); // safe conversion } |
Noncompliant Code Example AtomicInteger
...
Code Block | ||
---|---|---|
| ||
class InventoryManager {
private final AtomicInteger itemsInInventory = new AtomicInteger(100);
//...
public final void nextItem() {
itemsInInventory++;
}
}
|
Consequently, itemsInInventory
may wrap around to Integer.MIN_VALUE
after the increment operation.
...
Wiki Markup |
---|
The arguments to the {{compareAndSet()}} method are the expected value of the variable when the method is invoked and the intended new value. The variable's value is updated if, and only if, the current value and the expected value are equal (see \[[API 2006|AA. Bibliography#API 06]\] class [{{AtomicInteger}}|http://download.oracle.com/javase/6/docs/api/java/util/concurrent/atomic/AtomicInteger.html]). Refer to guideline [VNA02-J. Ensure that compound operations on shared variables are atomic|VNA02-J. Ensure that compound operations on shared variables are atomic] for more details. |
...