Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

 

Conversions of numeric types to narrower types can result in lost or misinterpreted data if the value of the wider type is outside the range of values of the narrower type. As a resultConsequently, all narrowing conversions must be guaranteed safe by range-checking the value before conversion.

There are Java provides 22 possible narrowing primitive conversions in Java. According to the The Java Language Specification (JLS), §5.1.3, "Narrowing Primitive Conversions" [JLS 2005]:

...

From

To

Description

Possible Resulting Errors

signed Signed integer

integral Integral type T

Keeps only n lower-order bits

Lost or misinterpreted data

char

integral Integral type T

Keeps only n lower-order bits

Magnitude error; negative number even though char is 16-bit unsigned

...

1. When converting a floating-point value to an int or long and the value is a NaN, a zero value is produced. Otherwise, if the value is not infinity, it is rounded towards toward zero to an integer value V:

...

  • The value is negative infinity or a value too negative to be represented, and Integer.MIN_VALUE or Long.MIN_VALUE is produced.
  • The value is positive infinity or a value too positive to be represented, and Integer.MAX_VALUE or Long.MAX_VALUE is produced.

...

See the JLS, §5.1.3, "Narrowing Primitive Conversions," [JLS 2005] for more information.

...

Narrower primitive types can be cast to wider types without affecting the magnitude of numeric values . See (see the JLS, §5.1.2, Widening Primitive Conversion" [JLS 2005]), for more information. Conversion from int or long to float or from long to double can lead to loss of precision (loss of least significant bits). No runtime exception occurs despite this loss.

Note that conversions from float to double or from double to float can also lose information about the overall magnitude of the converted value . See (see rule NUM53-J. Use the strictfp modifier for floating-point calculation consistency across platforms for additional information).

Noncompliant Code Example (Integer Narrowing)

In this noncompliant code example, a value of type int is converted to a value of type byte without range checking.:

Code Block
bgColor#FFcccc
class CastAway {
  public static void main(String[] args) {
    int i = 128;
    workWith(i);
  }

  public static void workWith(int i) {
    byte b = (byte) i;  // b has value -128
    // workWork with b
  }
}

The resulting value may be unexpected because the initial value (128) is outside of the range of the resulting type.

...

This compliant solution validates that the value stored in the wider integer type is within the range of the narrower type before converting to the narrower type.   It throws an ArithmeticException if the value is out of range.

Code Block
bgColor#ccccff
class CastAway {
  public static void workWith(int i) {
    // checkCheck ifwhether i is within byte range
    if ((i < Byte.MIN_VALUE) || (i > Byte.MAX_VALUE)) { 
      throw new ArithmeticException("Value is out of range");
    }

    byte b = (byte) i;
    // workWork with b
  } 
}

 Alternatively, the workWith() method can explicitly narrow when the programmer's intent is to truncate the value.:

Code Block
bgColor#ccccff
class CastAway {
   public static void workWith(int i) { 
     byte b = (byte)(i % 0x100); // 2^8;
     // workWork with b
   }
}

Range-checking is unnecessary because the truncation that is normally implicit in a narrowing conversion is made explicit. The compiler will optimize the operation away, and for that reason, no performance penalty is incurred.   Similar operations may be used for converting to other integral types.

...

The narrowing primitive conversions in this noncompliant code example suffer from loss in the magnitude of the numeric value as well as a loss of precision.:

Code Block
bgColor#FFcccc
float i = Float.MIN_VALUE;
float j = Float.MAX_VALUE;
short b = (short) i;
short c = (short) j;

The minimum and maximum float values are converted to minimum and maximum int values (0x80000000 and 0x7fffffff respectively). The resulting short values are the lower 16 bits of these values (0x0000 and 0xffff). The resulting final values (0 and -1−1) might be unexpected.

Compliant Solution (Floating-Point to Integer Conversion)

...

Code Block
bgColor#ccccff
float i = Float.MIN_VALUE;
float j = Float.MAX_VALUE;
if ((i < Short.MIN_VALUE) || (i > Short.MAX_VALUE) ||
    (j < Short.MIN_VALUE) || (j > Short.MAX_VALUE)) {
  throw new ArithmeticException ("Value is out of range");
}

short b = (short) i;
short c = (short) j;
// otherOther operations

Noncompliant Code Example (double to float Conversion)

The narrowing primitive conversions in this noncompliant code example suffer from a loss in the magnitude of the numeric value as well as a loss of precision. Because Double.MAX_VALUE is larger than Float.MAX_VALUE, c receives the value infinity, and because Double.MIN_VALUE is smaller than Float.MIN_VALUE, b receives the value 0.

...

Code Block
bgColor#ccccff
double i = Double.MIN_VALUE;
double j = Double.MAX_VALUE;
if ((i < Float.MIN_VALUE) || (i > Float.MAX_VALUE) ||
    (j < Float.MIN_VALUE) || (j > Float.MAX_VALUE)) {
  throw new ArithmeticException ("Value is out of range");
}

float b = (float) i;
float c = (float) j;
// otherOther operations

...

Risk Assessment

Casting a numeric value to a narrower type can result in information loss related to the sign and magnitude of the numeric value. As a result, data can be misrepresented or interpreted incorrectly.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

NUM12-J

lowLow

unlikelyUnlikely

mediumMedium

P2

L3

Automated Detection

Automated detection of narrowing conversions on integral types is straightforward. Determining whether such conversions correctly reflect the intent of the programmer is infeasible in the general case. Heuristic warnings could be useful.

...

Bibliography

...