
Numeric promotions are used to convert the operands of a numeric operator to a common type so that an operation can be performed. When using binary arithmetic operators with mixed operand sizes, be aware that some of the narrower operands may be are promoted to a wider type, to match the type of the other operand. For example in the expression a == 42
, the field a
which is shorter than an int
will be promoted to an int
before the comparison is carried out.
Wiki Markup |
---|
According to the Java Language Specification \[[JLS 05|AA. Java References#JLS 05]\], section 4.2.2 "Integer Operations": |
If an integer operator other than a shift operator has at least one operand of type
long
, then the operation is carried out using 64-bit precision, and the result of the numerical operator is of typelong
. If the other operand is notlong
, it is first widened (§5.1.5) to typelong
by numeric promotion (§5.6). Otherwise, the operation is carried out using 32-bit precision, and the result of the numerical operator is of typeint
. If either operand is not anint
, it is first widened to typeint
by numeric promotion.
wider operand.
Promotion Rules
The Java Language Specification (JLS), §5.6, "Numeric Promotions" [JLS 2013], describes numeric promotion as the following: The Java Language Specification \[[JLS 05|AA. Java References#JLS 05]\] section 5.6 "Numeric Promotions" describes numeric promotion as: Wiki Markup
- If any of the operands is of a reference type, unboxing conversion is performed. Then:
- If either operand is of type
double
, the other is converted todouble
.- Otherwise, if either operand is of type
float
, the other is converted tofloat
.- Otherwise, if either operand is of type
long
, the other is converted tolong
.- Otherwise, both operands are converted to type
int
.
Widening conversions, resulting from integer promotions, preserve the overall magnitude of the number. However, promotions in which the operands are converted from a numeric type such as an int
to a float
or from a long
to a double
, are particularly pernicious (see INT33-J. Do not cast numeric types to wider floating-point types without range checking for more details). These implicit casts can lead to loss of precision. can cause a loss of precision. (See NUM13-J. Avoid loss of precision when converting primitive integers to floating-point for more details.)
These conversions can occur when using the multiplicative operators These conversions can happen with the following operators : multiplicative operators (%, *, /), additive operators (+
, -
), comparison operators (<
, >
, <=
, >=
), equality operators (==
, !=
), and the integer bitwise operators (&
, |
, ^
).
Examples
In the following example, a
is promoted to a double
before the +
operator is applied.:
Code Block |
---|
int a = some_value;
double b = some_other_value;
double c = a + b;
|
As another example, considerIn the following program fragment, b
is first converted to int
so that the +
operator can be applied to operands of the same type:
Code Block |
---|
int a = some_value; char b = some_character; if ((a + b) > 1.1f) { //do Do something } |
Here, b
is first converted to int
so that the +
operator can be applied to operands of the same type. The result of (a + b)
is then converted to a float
, and the comparison operator is finally applied.
Also, see EXP04-J. Be wary of invisible implicit casts when using compound assignment operators and EXP05-J. Be careful of autoboxing when removing elements from a Collection.
...
Compound Operators
Type coercion may occur when compound expressions are used with mixed operand types. Examples of compound assignment operators are +=
, -=
, *=
, /=
, &=
, ^=
, %=
, <<=
, >>=
, >>>=
, and |=
.
According to the JLS, §15.26.2, "Compound Assignment Operators" [JLS 2013],
A compound assignment expression of the form
E1 op= E2
is equivalent toE1 = (T)((E1) op (E2))
, whereT
is the type ofE1
, except thatE1
is evaluated only once.
That is, the compound assignment expression implicitly casts the resulting computation to the type of the left-hand operand.
When the operands are different types, multiple conversions can occur. For example, when E1
is an int
and E2
is either a long
, a float
, or a double
, then E1
is widened from type int
to the type of E2
(before the "op
"), followed by a narrowing conversion from the type of E2
back to type int
(after the "op
" but before the assignment).
Noncompliant Code Example (Multiplication)
In this noncompliant code example, the statement big * one
carries out a binary operation. As big
is a variable of type int
and one
is (big)
is multiplied by a value of type float
, big
is promoted to the type float
. This implicit cast results in loss of precision. (one)
.
Code Block | ||
---|---|---|
| ||
class Test{ public static void main(String[] args){ int big = 1999999999; float one = 1.0f; // binaryBinary operation, loses precision because of implicit cast System.out.println(big * one); } } |
In this case, numeric promotions require that big
be promoted to the type float
before the multiplication occurs, resulting in loss of precision. (See NUM13-J. Avoid loss of precision when converting primitive integers to floating-point.). This code outputs 2.0E9 whereas, the expected output is rather than 1.999999999E9.
Compliant Solution (Multiplication)
This compliant solution uses the double
type, instead of float
, as a safer means of handling the widening primitive conversion resulting from integer promotion.:
Code Block | ||
---|---|---|
| ||
class Test{ public static void main(String[] args){ int big = 1999999999; double one = 1.0d; // doubleDouble instead of float System.out.println(big * one); } } |
This solution produces the required expected output of 1.999999999E9. This , which is the value that is obtained when an int
is assigned (implicitly cast) to a double
.
See also NUM50-J. Convert integers to floating point for floating-point operations for more information about mixing integer and floating-point arithmetic.
Noncompliant Code Example
...
(Left Shift)
This noncompliant code example shows integer promotion resulting from the use of the bit-wise bitwise OR operator. The byte array element is sign extended to 32 bits before it is used as an operand. If it contained the value {{0xff}}, now it would contain {{0xffffffff}} \[[Findbugs 08|AA. Java References#Findbugs 08]\].
Code Block | ||
---|---|---|
| ||
byte[] b = new byte[4]; | ||
Code Block | ||
| ||
int result = 0; for (int i = 0; i < 4; i++) { result = ((result << 8) | b[i]); } |
Each 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]. This causes result
to contain a value other than the concatenation of the four array elements.
Compliant Solution (Left Shift)
This compliant solution does not avoid integer promotion but works around it by masking masks off the upper 24 bits of the byte array element .to achieve the intended result:
Code Block | ||
---|---|---|
| ||
byte[] b = new byte[4]; int result = 0; for (int i = 0; i < 4; i++) { result = ((result << 8) | (b[i] & 0xff)); |
...
0xff);
} |
Noncompliant Code Example (Compound Addition and Assignment)
This noncompliant code example performs a compound assignment operation.
Code Block | ||
---|---|---|
| ||
int x = 2147483642; // 0x7ffffffa
x += 1.0f; // x contains 2147483647 (0x7fffffff)
// after the computation
|
The compound operation involves an int
value that contains too many significant bits to fit in the 23-bit mantissa of a Java float
, causing the widening conversion from int
to float
to lose precision. The resulting value is frequently unexpected.
Compliant Solution (Compound Addition and Assignment)
For defensive programming purposes, 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 | ||
---|---|---|
| ||
double x = 2147483642; // 0x7ffffffa
x += 1.0; // x contains 2147483643.0 (0x7ffffffb.0) as expected
|
Noncompliant Code Example (Compound Bit Shift and Assignment)
This noncompliant code example uses a compound right-shift operator for shifting the value of i
, bit.
Code Block | ||
---|---|---|
| ||
short i = -1;
i >>>= 1;
|
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. As a 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 performs an implicit narrowing conversion, discarding the 16 higher-order bits. The final result is again 0xffff
, or -1
.
Compliant Solution (Compound Bit Shift and Assignment)
This compliant solution applies the compound assignment operator to an int
, which does not require widening and subsequent narrowing. Consequently, i
gets the value 0x7fffffff
.
Code Block | ||
---|---|---|
| ||
int i = -1;
i >>>= 1;
|
Applicability
Failing to consider integer promotions when dealing with floating-point and integer operands can result in loss of precision.
...
Automated Detection
Severity Tool | Likelihood Version | Remediation Cost Checker | Priority Description Level | ||
---|---|---|---|---|---|
SonarQube | |||||
EXP08- J | low | probable | medium | P4 | L3 |
Automated Detection
TODO
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
References
Wiki Markup |
---|
\[[JLS 05|AA. Java References#JLS 05]\] 4.2.2 "Integer Operations" and 5.6 "Numeric Promotions"
\[[Findbugs 08|AA. Java References#Findbugs 08]\] "BIT: Bitwise OR of signed byte value" |
| S3034 |
Bibliography
Puzzle 9, "Tweedledum" | |
"BIT: Bitwise OR of Signed Byte Value" | |
[JLS 2013] | §4.2.2, "Integer Operations" |
...
EXP07-J. Do not diminish the benefits of constants by assuming their values in expressions 04. Expressions (EXP) EXP09-J. Use parentheses for precedence of operation