Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: The top-of-page comparison to C/C++ was irrelevant; changed method names to be clearer; deleted abs example because it was already used earliery

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 a null 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 an ArithmeticException if the right-hand operand is zero, and the increment and decrement operators ++ and -- which can throw an OutOfMemoryError 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

byte

--128 to 127

short

--32,768 to 32,767

int

--2,147,483,648 to 2,147,483,647

long

--9,223,372,036,854,775,808 to 9,223,372,036,854,775,807

char

\u0000 to \uffff (0 to 65,535)

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 a null 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 an ArithmeticException if the right-hand operand is zero, and the increment and decrement operators ++ and -- which can throw an OutOfMemoryError 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

byte

–128 to 127

short

–32,768 to 32,767

int

–2,147,483,648 to 2,147,483,647

long

–9,223,372,036,854,775,808 to 9,223,372,036,854,775,807

char

\u0000 to \uffff (0 to 65,535)

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 type long because long is already the largest primitive integer type.
  • BigInteger. Convert the inputs into objects of type BigInteger and perform all arithmetic using BigInteger methods. Type BigInteger 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 an ArithmeticException if the final result is outside the range of the original smaller type.

...

Code Block
bgColor#ccccff
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
bgColor#FFcccc
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
bgColor#ccccff
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
bgColor#ccccff

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
bgColor#ccccff
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
bgColor#FFcccc

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
bgColor#ccccff

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
bgColor#FFcccc
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.

...