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. Consequently, all narrowing conversions must be guaranteed safe by range-checking the value before conversion.

Java provides Every primitive numeric type in Java has a limited range that is strictly defined by the [JLS 2005]. There are 22 possible narrowing primitive conversions in Java. According to the The Java Languagee Specification (JLS), Section 5 §5.1.3, "Narrowing Primitive Conversions" [JLS 2015]:

  • short to byte or char
  • char to byte or short
  • int to byte, short, or char
  • long to byte, short, char, or int
  • float to byte, short, char, int, or long
  • double to byte, short, char, int, long, or float

Narrowing primitive conversions are allowed in cases where the value of the wider type is within the range of the narrower type.

Integer Narrowing

Integer type ranges are defined by the JLS, §4.2.1, "Integral Types and Values" [JLS 2015], and are also described in NUM00-J. Detect or prevent integer overflow.

The following table below presents the rules for narrowing primitive conversions of integer types. In the table, for an integer type T, n represents the number of bits used to represent the resulting type T (precision).

From

To

Description

Possible Resulting Errors

signed

Signed integer

integral

Integral type T

Keeps only n lower-order bits

Magnitude error; sign error

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

When integers are cast to narrow narrower data types, the magnitude of the numeric value and the corresponding sign can be affected. Consequently, data can be lost or misinterpreted.

Floating-

...

Point to Integer Conversion

Floating-point conversion to an integral type T is a two step procedure. The first step results in a long value if T is long; otherwise, it results in an int value. The second step narrows the int value to T if T is not int using the integer narrowing conversions outlined above. See JLS, Section 5.1.3, "Narrowing Primitive Conversions" for more information.-step procedure:

1. When converting a floating-point value to an int or long, the following logic is performed: If and the value is a NaN, STEP 1 produces an int or long a zero value is produced. Otherwise, if the value is not infinity, it is rounded towards toward zero to an integer value V, and there are two cases:

  • If T is long, and V can be represented as a long, then STEP 1 produces the long value V, is produced.
  • If or if V can be represented as an int, then STEP 1 produces the int value V is produced.

Otherwise, there must be one of two cases:

  • The value is negative infinity or a value too negative to be represented, and STEP 1 produces Integer.MIN_INTVALUE or Long.MIN_LONGVALUE is produced.
  • The value is positive infinity or a value too positive to be represented, and STEP 1 produces Integer.MAX_INTVALUE or MAX_LONG. Long.MAX_VALUE is produced.

2. If T is byte, char, or short, the result of the conversion is the result of a narrowing conversion to type T of the result of the first step

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

Other Conversions

Narrower primitive types can Narrower primitive types may be cast to wider types without affecting the magnitude of numeric values . See (see the JLS, Section 5§5.1.2, " Widening Primitive Conversion" [JLS 2005]), for more information). Conversion from int or long to float, or from long to double may 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 guideline FLP04(see NUM53-J. Use the strictfp modifier for floating-point calculation consistency across platforms for additional information).

Noncompliant Code Example (Integer Narrowing)

Consider the conversion from an integer to a byte. The higher order bytes of the integer are truncated and the lowest order byte is transferred to the target byte. However, because bytes store signed values, any value outside the range of -128 to +127 results in truncation and data loss. This noncompliant code example shows that an input of 128 yields a result value of -128. Similarly, 129 becomes -127 and so on. This is a consequence of interpreting the bit pattern of low order 8 bits of the input as a signed byte. For example, the binary representation of 129 is 10000001, which, as a byte, is interpreted as -127.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.

Compliant Solution (Integer Narrowing)

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

Code Block
bgColor#ccccff

class CastAway {
  public static void workWith(int i) {
    //check Check 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;
     // Work 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.

Noncompliant Code Example (Floating-

...

Point to

...

Integer Conversion)

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. In accordance with the language semantics quoted above, the :

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 0 and maximum int values (0x80000000 and 0x7fffffff respectively), and the . The resulting short values are 0 and the lower 16 bits of these values this value (0x0000 and 0xffff, respectively). The resulting final values (0 and -1−1) could be unexpected. might be unexpected.

Compliant Solution (Floating-Point to Integer Conversion)

This compliant solution range-checks both the i and j variables before converting to the resulting integer type. Because the maximum value is out of the valid range for a short, this code will always throw an ArithmeticException.

Code Block
bgColor#FFcccc#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;
// Other 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#FFcccc
double i = Double.MIN_VALUE;
double j = Double.MAX_VALUE;
float b = (float) i;
float c = (float) j;

Compliant Solution (

...

double to float Conversion)

This compliant solution performs Perform range checks on both i and j variables before proceeding with the conversions. Because both values are out of the valid range for a float, this code will always throw an ArithmeticException.

Code Block
bgColor#ccccff

floatdouble i = FloatDouble.MIN_VALUE;
floatdouble j = FloatDouble.MAX_VALUE;
if ((i < ShortFloat.MIN_VALUE) || (i > ShortFloat.MAX_VALUE) ||
    (j < ShortFloat.MIN_VALUE) || (j > ShortFloat.MAX_VALUE)) {
  throw new ArithmeticException ("Value is out of range");    
}

shortfloat b = (shortfloat) i;
shortfloat c = (shortfloat) j;
//other Other 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. ConsequentlyAs a result, data can be misrepresented or interpreted incorrectly.

Guideline

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

EXP13

NUM12-J

low

Low

unlikely

Unlikely

medium

Medium

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.

ToolVersionCheckerDescription
CodeSonar
Include Page
CodeSonar_V
CodeSonar_V

JAVA.MATH.APPROX.E
JAVA.MATH.APPROX.PI
JAVA.CAST.FTRUNC
JAVA.ARITH.FPEQUAL

Approximate e Constant (Java)
Approximate pi Constant (Java)
Cast: Integer to Floating Point (Java)
Floating Point Equality (Java)

Parasoft Jtest
Include Page
Parasoft_V
Parasoft_V
CERT.NUM12.CLPDo not cast primitive data types to lower precision

Related Guidelines

...

...

...

...

ISO/IEC TR 24772:2010

Numeric Conversion Errors [FLC]

MITRE CWE

CWE-681, Incorrect Conversion between Numeric Types

...


...

...

, Numeric Truncation Error

...

Bibliography

...

...

...


...

Image Added Image Added Image Added overflow      Integers (INT)      INT02-J. Do not assume that the remainder operator always returns a non-negative result