...
See the following example:
Noncompliant Code Example
In we have the following simple method the result could overflow
...
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 |
| |= | no |
| un + | no |
| || | no |
yes |
| ^= | no |
| yes |
| ?: | no |
Addition
Addition (and all operations) in Java are performed in signed numbers as Java does not support unsigned numbers
Noncompliant Code Example
In this example the addition could result in overflow
Code Block | ||
---|---|---|
| ||
public int do_operation(int a,int b) { int temp = a + b; //Could result in overflow //do other processing return temp; } |
Compliant Solution (Bounds Checking)
A solution would be to explicitly check the range of each arithmetic operation and throw an ArithmeticException on overflow, otherwise downcast the value to an integer. For arithmetical operations on really big numbers one should always use the BigInteger Class
...
e.g for the previous example
Compliant Solution (Use long and downcast)
Code Block | ||
---|---|---|
| ||
public int do_operation(int a, int b) throws ArithmeticException { long temp = (long)a+(long)b; if(temp >Integer.MAX_VALUE || temp < Integer.MIN_VALUE) throw ArithmeticException; else //Value within range can perform the addition //Do stuff return (int)temp; } |
Compliant Solution (Bounds Checking)
Another example would be of explicit range checking would be:
Code Block | ||
---|---|---|
| ||
public int do_operation(int a, int b) throws ArithmeticException { int temp; if(a>0 && b>0 && (a >Integer.MAX_VALUE - b) || a<0 && b<0 && (a < Integer.MIN_VALUE -b)) throw ArithmeticException; else temp = a + b;//Value within range can perform the addition //Do stuff return temp; } |
Compliant Solution (Use BigInteger class)
Another compliant approach would be to use the BigInteger class in this example and in the examples of the other operations using a wrapper for test of the overflow:
...
By using the BigInteger class there is no chance to overflow (see section on BigInteger class) but the performance is degraded so it should be used only on really large operations
Subtraction
Care must be taken in subtraction operations as well as these can overflow as well.
Noncompliant Code Example
Code Block | ||
---|---|---|
| ||
public int do_operation(int a,int b) { int temp = a - b; //Could result in overflow //perform other processing return temp; } |
Compliant Code Example (Use long)
The appropriate way is to check explicitely the range before doing the subtraction
Code Block | ||
---|---|---|
| ||
int a,b,result; long temp = (long)a-(long)b; if(long < Integer.MIN_VALUE || long > Integer.MAX_VALUE) throw ArithmeticException; else result = (int) temp; |
Compliant Code Example (Use BigInteger class)
A BigInteger class as a test-wrapper could be used
Code Block | ||
---|---|---|
| ||
public bool underflow(int a, int b) { java.math.BigInteger ba = new java.math.BigInteger(String.valueOf(a)); java.math.BigInteger bb = new java.math.BigInteger(String.valueOf(b)); java.math.BigInteger br = ba.subtract(bb); if(br.compareTo(java.math.BigInteger.valueOf(Integer.MAX_VALUE)) == 1 || br.compareTo(java.math.BigInteger.valueOf(Integer.MIN_VALUE))== -1) return true;//We have underflow //Can proceed return false } public int do_operation(int a, int b) throws ArithmeticException { if(undeflow(a,b)) throw ArithmeticException; else //we are within range safely perform the addition } |
Multiplication
This noncompliant code example, can result in a signed integer overflow during the multiplication of the signed operands a and b. If this behaviour is unanticipated, the resulting value may lead to undefined behaviour
Noncompliant Code Example
Code Block | ||
---|---|---|
| ||
int a,b,result //do stuff result = a*b;//May result in overflow |
Compliant Code Example
Since in this platform the size of type long (64 bits) is twice the size of type int (32 bits) we should perform the multiplication in terms of long and if the product is in the integer range we downcast the result to int
Code Block | ||
---|---|---|
| ||
int a,b,result; long temp = (long) a\* (long)b; if(temp > Integer.MAX_VALUE || temp < Integer.MIN_VALUE) throw ArithmeticException;//overflow else result = (int) temp;//Value within range, safe to downcast |
Division
Although Java throws a java.lang.ArithmeticException: / by zero exception for division by zero, there is the same issue as in C\C++ when dividing the Integer.MIN_VALUE with -1. It produces Integer.MIN_VALUE unexpectedly
...
A non-compliant example is:
Noncompliant Code Example
Code Block | ||
---|---|---|
| ||
int a,b,result result = a/b; |
Compliant Code Example
Code Block | ||
---|---|---|
| ||
if(a == Integer.MIN_VALUE && b == -1) throw ArithmeticException;//May be Integer.MIN_VALUE again???? else result = a/b;//safe operation |
Modulo
Modulo operation is safer in Java than C/C++
...
-if the right-hand operand is zero then the integer remainder operator %, will throw an ArithmeticException
Unary Negation
If we negate Integer.MIN_VALUE we get Integer.MIN_VALUE. So we explicitely check the range
Noncompliant Code Example
Code Block | ||
---|---|---|
| ||
int temp = -result; |
Compliant Code Example
Code Block | ||
---|---|---|
| ||
if(a == Integer.MIN_VALUE) throw ArithmeticException; else result = -a; |
SHIFTING
The shift in java is quite different than in C\C++.
...
Code Block | ||
---|---|---|
| ||
public int do_shift(int shift_value){Â if(shift_value > 31 or shift_value <0) throw ArithmeticException; else int val = 2 << shift_value; } |
Unsigned Right shifting >>>
It is identical to the right-shift operator if the shifted value is positive. If it is negative the sign value can change because the left-operand high-order bit is not retained and the sign value can change; Excerpt from JLS:
"if n is negative, the result is equal to that of the expression (n>>s)(2<<~s) if the type of the left-hand operand is int, and to the result of the expression (n>>s)(2L<<~s) if the type of the left-hand operand is long. The added term (2<<~s) or (2L<<~s) cancels out the propagated sign bit. (Note that, because of the implicit masking of the right-hand operand of a shift operator, ~s as a shift distance is equivalent to 31-s when shifting an int value and to 63-s when shifting a longvalue.)"
For example: -32 >>> 2 = (-32 >> 2 ) + ( 2 << ~2 ) = 1073741816
Operations Requiring Really Long Numbers
For these operations the BigInteger class should be used. According to SUN BigInteger Class:
...
For instance operations on long are operations on 64 bits. For example addition:
Compliant Code Example
Code Block | ||
---|---|---|
| ||
java.math.BigInteger big_long_max = new java.math.BigInteger(String.valueOf(Long.MAX_VALUE)); System.out.println("big_long="+big_long_max); big_long_max = big_long_max.add(java.math.BigInteger.valueOf(1));//same as ++big_long_max System.out.println("big_long="+big_long_max); These print big_long=9223372036854775807 big_long=9223372036854775808//exceeds the maximum range of long, no problem java.math.BigInteger big_long_min = new java.math.BigInteger(String.valueOf(Long.MIN_VALUE)); System.out.println("big_long_min="+big_long_min); big_long_min = big_long_min.subtract(java.math.BigInteger.valueOf(1));//same as --big_long_min System.out.println("big_long_min="+big_long_min);//goes bellow minimum range of long, no problem These print: big_long_min=-9223372036854775808 big_long_min=-9223372036854775809 if(big_long < Long.MAX_VALUE && big_long > Long.MIN_VALUE)//value within range can go to the primitive type long value = big_log.longValue();//get primitive type else //Perform error handling. We can not downcast since the value can not be represented as a long |
We can always go back to the primitive types if the BigInteger of course can be represented by the type
In the example if big_long is within long range (big_long < Long.MAX_VALUE && big_long > Long.MIN_VALUE) we can use the BigInteger method longValue() to get the long value and assign it to a variable of type long
Risk Assesment
Integer overflows are among the most dangerous defects in software since it leads to exploitation, undefined and erroneous behavior
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
INT34-J | high | likely | high | P6 | L2 |
Other Languages
This rule appears as in the C++ Secure Coding standard as: INT32-CPP. Ensure that operations on signed integers do not result in overflow
This rule also appears in the C Secure Coding Standard as: INT32-C. Ensure that operations on signed integers do not result in overflow
References
Secure Coding Guidelines for the Java Programming Language: Secure (Paragraph on comparison C++/Java)
...