You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 58 Next »

When using binary operators with mixed operand sizes, be aware that some of the narrower operands may be 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.

According to the Java Language Specification 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 type long. If the other operand is not long, it is first widened (§5.1.5) to type long by numeric promotion (§5.6). Otherwise, the operation is carried out using 32-bit precision, and the result of the numerical operator is of type int. If either operand is not an int, it is first widened to type int by numeric promotion.

The JLS Section 5.6 Numeric Promotions describes numeric promotion as the following:

  1. If any of the operands is of a reference type, unboxing conversion is performed. Then:
  2. If either operand is of type double, the other is converted to double.
  3. Otherwise, if either operand is of type float, the other is converted to float.
  4. Otherwise, if either operand is of type long, the other is converted to long.
  5. 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 an int to a float or from a long to a double may cause unexpected loss of precision (see guideline INT03-J. Avoid casting numeric types to wider floating-point types without range checks for more details).

These conversions can happen with the following operators: multiplicative operators (%, *, /), additive operators (+, -), comparison operators (<, >, <=, >=), equality operators (==, !=) and the integer bitwise operators (&, |, ^).

In the following example, a is promoted to a double before the + operator is applied.

int a = some_value;
double b = some_other_value;
double c = a + b;

As another example, consider:

int a = some_value;
char b = some_character;

if((a + b) > 1.1f) {
  //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 guidelines EXP04-J. Beware of invisible implicit casts when using compound assignment operators and EXP11-J. Be careful of autoboxing when removing elements from a Collection.

Noncompliant Code Example

In this noncompliant code example, the statement big * one carries out a binary operation. As big is of type int and one is of type float, big is promoted to the type float. This implicit cast results in loss of precision.

class Test{
  public static void main(String[] args){
    int big = 1999999999;
    float one = 1.0f;
    // binary operation, loses precision because of implicit cast
    System.out.println(big * one); 
  }
}

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.

class Test{
  public static void main(String[] args){
    int big = 1999999999;
    double one = 1.0d; // double instead of float
    System.out.println(big*one);
  }
}

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

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]].

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 masks off the upper 24 bits of the byte array element to achieve the intended result.

int result = 0;
for(int i = 0; i < 4; i++) 
  result = ((result << 8) | (b[i] & 0xff));

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

[[JLS 2005]] Section 4.2.2, "Integer Operations" and Section 5.6, "Numeric Promotions"
[[Findbugs 2008]] "BIT: Bitwise OR of signed byte value"


EXP04-J. Beware of invisible implicit casts when using compound assignment operators      04. Expressions (EXP)      EXP06-J. Use parentheses for precedence of operation

  • No labels