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

Compare with Current View Page History

« Previous Version 6 Next »

The shift operators in Java have the following properties (Java Language Specification (JLS) §15.19, "Shift Operators") [JLS 2005]:

  • The >> right shift is an arithmetic shift; the >>> right shift is a logical shift.
  • The types boolean, float, and double cannot use the bit shifting operators.
  • When the value to be shifted is of type int, only the five lowest-order bits of the right-hand operand are used as the shift distance. That is, the shift distance is the value of the right-hand operand masked by 31 (0x1F). The shift distance actually used is consequently always in the range 0 to 31, inclusive.
  • When the value to be shifted (left-operand) is type long, only the last 6 bits of the right-hand operand are used to perform the shift. The shift distance is the value of the right-hand operand masked by 63 (0x3F). The shift distance actually used is consequently always in the range 0 to 63, inclusive.

The value to the right of a shift operation must be within the appropriate range for the type of the numeric value to the left of the shift operation. That is, if the left numeric type is a long, the right value must be within the range [0, 63], otherwise the right value must be within the range [0, 31].

Arithmetic vs. Logical Shift

The JLS [JLS 2005] defines the behavior of the arithmetic shift operator as follows:

The value of n>>s is n right-shifted s bit positions with sign-extension. The resulting value is ⌊ n / 2 s ⌋. For nonnegative values of n, this is equivalent to truncating integer division, as computed by the integer division operator /, by two to the power s.

The JLS also defines the behavior of the logical shift operator:

The value of n>>>s is n right-shifted s bit positions with zero-extension. If n is positive, then the result is the same as that of n>>s; if n is negative, the result is equal to that of the expression (n>>s) + (2<<~s) if the type of the left-hand operand is int, and to the result of the expression (n>>s) + (2L<<~s) if the type of the left-hand operand is long. The added term (2<<~s) or (2L<<~s) cancels out the propagated sign bit. (Note that, because of the implicit masking of the right-hand operand of a shift operator, ~s as a shift distance is equivalent to 31-s when shifting an int value and to 63-s when shifting a long value.)

Never use the arithmetic shift operator when the logical shift operator is required.

Noncompliant Code Example (Arithmetic vs. Logical)

In this noncompliant code example, method countOneBits loops forever on negative inputs because the >> operator performs an arithmetic shift rather than a logical shift.

static int countOneBits(long value) {
  int bits = 0;
  while (value != 0) {
    bits += value & 1L;
    value >>= 1; // signed right-shift, by one
  }
  return bits;
}

Compliant Solution (Arithmetic vs. Logical)

This compliant solution uses the logical shift operator >>> which clears vacated bits (that is, shifts in zero-bits on the left).

static int countOneBits( long value ) {
  int bits = 0;
  while (value != 0) {
    bits += value & 1L;
    value >>>= 1;
  }
  return bits;
}

Promotion

Shift operands of type byte, short, or char are promoted to the type int. Operands of type int or long preserve their types. Unlike other arithmetic operators, promotion of the left operand of a shift operator is independent of the type of the right operand. Consequently, a left operand of type byte is promoted to type int, even when the shift distance (the right operand) is type long.

Noncompliant Code Example (Promotion)

In this noncompliant code example, the programmer intends to shift a byte value two bits to the right (with zero fill). However, the JLS specifies that the left operand must be promoted to either type int or type long (int, in this case); this promotion performs sign extension. Because of the promotion, the result of the shift for negative input values will be a large positive number, and the programmer could find this surprising.

byte b = /* initialize */;
int result = b >>> 2;

Compliant Solution (Promotion)

This compliant solution uses a bitmask to clear the upper 24 bits (whose value was produced by sign extension), generating the intended result.

byte b = /* initialize */;
int result = ((int) b & 0xFF) >>> 2;

The explicit cast to type int is redundant, but it clarifies the expected type.

Truncation of Shift Distance

When the left-hand operand is of type int, the right-hand operand (exp) is masked by 31 (0x1F). A left operand of type long causes the right operand (exp) to be masked by 63 (0x3F). Consequently, when the shift distance is greater than the number of bits in the left-hand operand, the shift distance is interpreted as being (distance % number_of_bits).

Noncompliant Code Example (Truncation)

This noncompliant code example fails to perform explicit range checking to avoid truncation of the shift distance.

public int doOperation(int exp) {
  // compute 2^exp
  int temp = 1 << exp;
  // do other processing
  return temp;
}

Compliant Solution (Truncation)

This compliant solution range checks the shift distance to avoid unexpected behavior.

public int doOperation(int exp) throws ArithmeticException {
  if ((exp < 0) || (exp >= 32)) {
    throw new ArithmeticException("Exponent out of range");
  }
  // safely compute 2^exp
  int temp = 1 << exp;
  // do other processing
  return temp;
}

Explicit range checking for arithmetic operations is detailed in the rule NUM00-J. Detect or prevent integer overflow.

Noncompliant Code Example (Truncation Zeroing)

This noncompliant code example tries to shift the value -1 by increasing the value of i until, after 32 iterations, the programmer believes the result would become 0. The loop actually never terminates because an attempt to shift a value of type int by 32 bits results in the original value (that is, -1) rather than the expected value 0 [Bloch 2005]. This is because only the least significant 5 bits of i is considered when the shift, and when i reaches the value 32, the 5 least significant bits have the value 0.

int i = 0;
while ((-1 << i) != 0) {
  i++;
}

Compliant Solution (Truncation Zeroing)

This compliant solution does 32 shifts in succession, achieving the value 0 on the 32nd iteration.

for (int val = -1; val != 0; val <<= 1) { /* ... */ }

Multiplication and Division

See rule NUM01-J. Do not perform bitwise and arithmetic operations on the same data.

Risk Assessment

Incorrect use of shift operators can lead to unanticipated results, causing erratic control flow or unanticipated program behavior.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

NUM14-J

low

probable

medium

P4

L3

Automated Detection

Automatic detection of shift operators is straightforward. Sound determination of whether the usage of those shift operators correctly reflects the intent of the programmer is infeasible in the general case. Heuristic warnings could be useful.

Related Guidelines

Bibliography

 


  • No labels