...
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 Java Language Specification, Section 4.2.1, "Integral Types and Values," and are also described in INT00-J. Ensure that integer operations do not result in overflow.
...
When integers are cast to narrow data types, the magnitude of the numeric value and the corresponding sign can be affected. Consequently, data can be lost or misinterpreted.
Floating-point Conversion to Integer
Floating-point conversion to an integral type T
is a two step procedure:
...
See JLS, Section 5.1.3, "Narrowing Primitive Conversions" for more information.
Other Conversions
Narrower primitive types may be cast to wider types without affecting the magnitude of numeric values. See JLS, Section 5.1.2, "Widening Primitive Conversion" for more information. Conversion from int
or long
to float
, or long
to double
may 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 double
to float
can also lose information about the overall magnitude of the converted value. See guideline FLP04-J. Use the strictfp modifier for floating point calculation consistency 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.
...
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 that the value stored in the wider integer type is within the range of the narrower type before converting to the narrower type.
Code Block | ||
---|---|---|
| ||
class CastAway { public static void workWith(int i) //check if 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; // work with b } } |
Noncompliant Code Example (Floating-point Conversion to Integer)
The narrowing primitive conversions in this noncompliant code example suffers from loss in the magnitude of the numeric value, as well as a loss of precision.
...
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) might be unexpected.
Compliant Solution (Floating-point Conversion to Integer)
This compliant solution range checks both the i
and j
variables before converting to the resulting integer type.
Code Block | ||
---|---|---|
| ||
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
Conversion to float
)
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. 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
, d
receives the value 0
.
Code Block | ||
---|---|---|
| ||
double i = Double.MIN_VALUE; double j = Double.MAX_VALUE; float b = (float) i; float c = (float) j; |
Compliant Solution (double
Conversion to float
)
Perform range checks on both i
and j
variables before proceeding with the conversions.
Code Block | ||
---|---|---|
| ||
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; //other operations |
Exceptions
EXP13-EX0: Java's narrowing conversions are both well-defined and portable; knowledgeable programmers can intentionally apply such conversions in contexts where their output is both expected and reasonable. Consequently, narrowing conversions are permitted when the code contains comments that document both the use of narrowing conversions and that the potential for truncation has been anticipated. A suitable comment might read: "// Deliberate narrowing cast of i; possible truncation OK"
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. Consequently, data can be misrepresented or interpreted incorrectly.
Guideline | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
EXP13 NUM00-J | low | unlikely | 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.
Related Guidelines
C Secure Coding Standard: INT31-C. Ensure that integer conversions do not result in lost or misinterpreted data
C Secure Coding Standard: FLP34-C. Ensure that floating point conversions are within range of the new type
C++ Secure Coding Standard: INT31-CPP. Ensure that integer conversions do not result in lost or misinterpreted data
C++ Secure Coding Standard: FLP34-CPP. Ensure that floating point conversions are within range of the new type
MITRE CWE: CWE-681 "Incorrect Conversion between Numeric Types"
MITRE CWE: CWE-197 "Numeric Truncation Error"
Bibliography
[Harold 1999]
[JLS 2005] Section 5.1.3, "Narrowing Primitive Conversions"
...