...
Code Block |
---|
static final preAdd(int left, int right) throws ArithmeticException { if (right > 0 ? left > Integer.MAX_VALUE - right : left < Integer.MIN_VALUE - right) { throw new ArithmeticException("Integer overflow"); } } static final preSubtract(int left, int right) throws ArithmeticException { if (right > 0 ? left < Integer.MIN_VALUE + right : left > Integer.MAX_VALUE + right) { throw new ArithmeticException("Integer overflow"); } } static final preMultiply(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"); } } static final preDivide(int left, int right) throws ArithmeticException { if ((left == Integer.MIN_VALUE) && (right == -1)) { throw new ArithmeticException("Integer overflow"); } } static final preAbs(int a) throws ArithmeticException { if (a == Integer.MIN_VALUE) { throw new ArithmeticException("Integer overflow"); } } static final preNegate(int a) throws ArithmeticException { if (a == Integer.MIN_VALUE) { throw new ArithmeticException("Integer overflow"); } } |
Note that although these pre-conditioning checks are correct, more efficient code may well be possible. Further, the checks can be simplified when the original type was char
. Because the range of type char
includes only positive values, all comparisons with negative values may be omitted.
...
Code Block | ||
---|---|---|
| ||
private static final BigInteger bigMaxInt = BigInteger.valueOf(Integer.MAX_VALUE); private static final BigInteger bigMinInt = BigInteger.valueOf(Integer.MIN_VALUE); public BigInteger intRangeCheck(BigInteger val) throws ArithmeticException { if (val.compareTo(bigMaxInt) == 1 || val.compareTo(bigMinInt) == -1) { throw new ArithmeticException("Integer overflow"); } return val; } public 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 } |
Exceptions
AtomicInteger
Operations on objects of type AtomicInteger
suffer from the same overflow issues as do the other integer types. The solutions are generally similar to those shown above; however, concurrency issues add additional complications. First, avoid possible issues with time-of-check-time-of-use (see VNA02-J. Ensure that compound operations on shared variables are atomic for more information). Secondly, use of an AtomicInteger
creates happens-before relationships between the various threads that access it. Consequently, changes to the number or order of accesses may alter the execution of the overall program. In such cases you must either choose to accept the altered execution or carefully craft the implementation of your compliant technique to preserve the exact number and order of accesses to the AtomicInteger
.
Noncompliant Code Example
This noncompliant code example uses an AtomicInteger which is part of the concurrency utilities. The concurrency utilities lack integer overflow checks.
Code Block | ||
---|---|---|
| ||
class InventoryManager {
private final AtomicInteger itemsInInventory = new AtomicInteger(100);
//...
public final void returnItem() {
itemsInInventory++;
}
}
|
Consequently, itemsInInventory may wrap around to Integer.MIN_VALUE after the increment operation.
Compliant Solution
This compliant solution uses the get()
and compareAndSet()
methods provided by AtomicInteger
to guarantee successful manipulation of the shared value of itemsInInventory
. Note that:
- The number and order of accesses to
itemsInInventory
remains unchanged from the noncompliant code example. - All operations on the value of
itemsInInventory
are performed on a temporary local copy of its value. - The overflow check in this example is performed in open code, rather than encapsulated in a method call. This is an acceptable alternative implementation. The choice of method call vs. open code should be made according to your organization's standards and needs.
Code Block | ||
---|---|---|
| ||
class InventoryManager {
private final AtomicInteger itemsInInventory = new AtomicInteger(100);
public final void returnItem() {
while (true) {
int old = itemsInInventory.get();
if (old == Integer.MAX_VALUE) {
throw new ArithmeticException("Integer overflow");
}
int next = old + 1; // Increment
if (itemsInInventory.compareAndSet(old, next)) {
break;
}
} // end while
} // end removeItem()
}
|
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 will be updated if and only if the current value and the expected value are equal \[[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] for more details. |
Exceptions
INT00-EX1: Depending on circumstances, integer overflow may be benign. For instance, the Object.hashcode()
method may INT00-EX1: Depending on circumstances, integer overflow may be benign. For instance, the Object.hashcode()
method may return all representable values of type int
; further, many algorithms for computing hashcodes intentionally allow overflow to occur.
INT00-EX2: The added complexity and cost of programmer-written overflow checks may exceed their value for all but the most-critical code. In such cases, consider the alternative of treating integral values as though they are tainted data, using appropriate range checks as the notional "sanitizing" code. These range checks should ensure that incoming values cannot cause integer overflow. Note that sound determination of allowable ranges may require deep understanding of the details of the code protected by the range checks; this is non-trivialcorrect determination of the allowable ranges may be extremely difficult.
Risk Assessment
Failure to perform appropriate range checking can lead to integer overflows, which may cause unexpected program control flow or unanticipated program behavior.
...
This guideline appears in the C++ Secure Coding Standard as INT32-CPP. Ensure that operations on signed integers do not result in overflow.
Bibliography
Wiki Markup |
---|
\[[API 2006|AA. Bibliography#API 06]\] class [{{AtomicInteger}}|http://download.oracle.com/javase/6/docs/api/java/util/concurrent/atomic/AtomicInteger.html]
\[[Bloch 2005|AA. Bibliography#Bloch 05]\] Puzzle 27: Shifty i's\[[SCG 2007|AA. Bibliography#SCG 07]\] Introduction
\[[JLS 2003|AA. Bibliography#JLS 03]\] 4.2.2 Integer Operations and 15.22 Bitwise and Logical Operators
\[[MITRE 2009|AA. Bibliography#MITRE 09]\] [CWE ID 682|http://cwe.mitre.org/data/definitions/682.html] "Incorrect Calculation", [CWE ID 190|http://cwe.mitre.org/data/definitions/190.html] "Integer Overflow or Wraparound", [CWE ID 191|http://cwe.mitre.org/data/definitions/191.html] "Integer Underflow (Wrap or Wraparound)"
\[[Seacord 2005|AA. Bibliography#Seacord 05]\] Chapter 5. Integers
\[[Tutorials 2008|AA. Bibliography#Tutorials 08]\] Primitive Data Types |
...