...
One or more implicit invisible conversions occur when the operands are different types. When E1 is an int and E2 is either a long, a float, or a double, for example, there will be two conversions: first, a widening conversion on E1 from int to the type of E2 (before the "op"), and, second, a narrowing conversion from the type of E2 back to int (after the "op" and before the assignment).
Noncompliant Code Example
In this noncompliant code example, the statement big * one carries out a binary operation. Because big is type int, and one is type float, big is promoted to the type float. This implicit cast results in loss of precision.
...
This code outputs 2.0E9 whereas, the expected output is 1.999999999E9.
Compliant Solution
This compliant solution uses the double type, instead of float, as a safer means of handling the widening primitive conversion resulting from integer promotion.
...
This produces the expected output of 1.999999999E9. This is the value that is obtained when an int is assigned (implicitly cast) to a double.
Noncompliant Code Example
| Wiki Markup |
|---|
This noncompliant code example shows integer promotion resulting from the use of the bit-wise OR operator. The byte array element is sign extended to 32 bits before it is used as an operand. If it originally contained the value {{0xff}}, it would contain {{0xffffffff}} \[[Findbugs 2008|AA. Bibliography#Findbugs 08]\]. |
| Code Block | ||
|---|---|---|
| ||
int result = 0; for(int i = 0; i < 4; i++) result = ((result << 8) | b[i]); |
Compliant Solution
This compliant solution continues to use integer promotion, but it masks off the upper 24 bits of the byte array element to achieve the intended result.
| Code Block | ||
|---|---|---|
| ||
int result = 0; for(int i = 0; i < 4; i++) result = ((result << 8) | (b[i] & 0xff)); |
Noncompliant Code Example
This noncompliant code example performs a compound assignment operation. This operation involves an int value that contains too many significant bits to fit in the twenty-three bit mantissa of a Java float, causing the widening conversion from int to float to lose precision. The resulting value could surprise many programmers.
| Code Block | ||
|---|---|---|
| ||
public class Expr {
public static void main(String[] args) {
int x = 2147483642; // 0x7ffffffa
x += 1.0f; // x contains 2147483647 (0x7fffffff) after the computation
}
}
|
Compliant Solution
To be safe, avoid using any of the compound assignment operators on variables of types byte, short or char. Also, refrain from using a wider operand on the right hand side. In this compliant solution, all operands are of the Java type double.
| Code Block | ||
|---|---|---|
| ||
public class Expr {
public static void main(String[] args) {
double x = 2147483642; // 0x7ffffffa
x += 1.0; // x contains 2147483643.0 (0x7ffffffb.0) as expected
}
}
|
Noncompliant Code Example
This noncompliant code example uses a compound right shift operator for shifting the value of i, bit by bit. Unfortunately, the value of i remains the same. The value of i is first promoted to an int. This is a widening primitive conversion, so no data is lost. With short, -1 is represented as 0xffff. The conversion to int results in the value 0xffffffff, which is right shifted by 1 bit to yield 0x7fffffff. To store the value back into the short variable i, Java then performs an implicit narrowing conversion, discarding the 16 higher order bits. The final result is again 0xffff or -1.
| Code Block | ||
|---|---|---|
| ||
short i = -1; i >>>= 1; |
Compliant Solution
This compliant solution applies the compound assignment operator to an int which does not require widening and subsequent narrowing.
| Code Block | ||
|---|---|---|
| ||
int i = -1; i >>>= 1; |
Risk Assessment
Failing to consider integer promotions when dealing with floating point and integer operands can result in loss of precision.
Guideline | Severity | Likelihood | Remediation Cost | Priority | Level |
|---|---|---|---|---|---|
EXP05-J | low | probable | medium | P4 | L3 |
Automated Detection
Automated detection of numeric promotion is straightforward. Determining which promotions may be problematic is infeasible in the general case. A heuristic approach may provide acceptable results.
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this guideline on the CERT website.
Bibliography
| Wiki Markup |
|---|
\[[Bloch 2005|AA. Bibliography#Bloch 05]\] Puzzle 9: "Tweedledum," and Puzzle 31: "Ghost of Looper" \[[Findbugs 2008|AA. Bibliography#Findbugs 08]\] "BIT: Bitwise OR of signed byte value" \[[JLS 2005|AA. Bibliography#JLS 05]\] [Section 4.2.2|http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.2.2], "Integer Operations", [Section 5.6|http://java.sun.com/docs/books/jls/third_edition/html/conversions.html#5.6], "Numeric Promotions", and [Section 15.26.2|http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.26.2], "Compound Assignment Operators" |
...