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

Compare with Current View Page History

« Previous Version 14 Next »

Integer variables are frequently intended to represent either a numeric value or a bit collection. Numeric values should be exclusively operated upon using arithmetic operations, while bit collections should be exclusively operated upon using logical operations. However, it is difficult for an analyzer to determine the intended usage of a particular integer variable.

Performing bitwise and arithmetic operations on the same data suggests confusion as to the purpose of the data stored in the variable. Unfortunately, bitwise operations are frequently performed on arithmetic values as a form of premature optimization. Bitwise operators include the unary operator ~ and the binary operators <<, >>, &, ^, and |. Although such operations are valid and will compile, they can reduce code readability.

Noncompliant Code Example (Left Shift)

Left- and right-shift operators are often employed to multiply or divide a number by a power of 2. This compromises code readability and portability for the sake of often-illusory speed gains. The JVM will usually make such optimizations automatically, and unlike a programmer, the JVM can optimize for the implementation details of the current platform. In this noncompliant code example, both bit manipulation and arithmetic manipulation are performed on the integer x that conceptually contains a numeric value. The result is a (prematurely) optimized statement that assigns 5x + 1 to x.

int x = 50;
x += (x << 2) + 1;

Compliant Solution (Left Shift)

In this compliant solution, the assignment statement is modified to reflect the arithmetic nature of x, resulting in a clearer indication of the programmer's intentions.

int x = 50;
x = 5 * x + 1;

A reviewer may now recognize that the operation should also be checked for overflow. This might not have been apparent in the original, noncompliant code example. For more information, see INT00-J. Ensure that integer operations do not result in overflow.

Noncompliant Code Example (Right Shift)

In this noncompliant code example, the programmer prematurely optimizes code by replacing a division with a right shift.

int x = -50;
x = x + 2;
x >>>= 2;

The >>>= operator is a logical right shift; it fills the leftmost bits with zeroes, regardless of the number's original sign. Using logical right shift for division produces an incorrect result when the dividend (x in this example) contains a negative value. Arithmetic right shift (the >>= operator) can replace division, as shown in the following example:

int x = -50;
x = x + 2;
x >>= 2;

However, the result is less maintainable than making the division explicit. Refer to guideline NUM04-J. Use shift operators correctly for examples of sign extension with respect to the shift operators.

Compliant Solution (Right Shift)

In this compliant solution, the right shift is replaced by division.

int x = -50;
x += 2
x /= 4;

Noncompliant Code Example

In this noncompliant code example, a programmer is attempting to fetch four values from a byte array and pack them into the the integer variable result. The integer value in this example represents a bit collection and not a numeric value.

// b[] is a byte array, initialized to 0xff
byte[] b = new byte[] {-1, -1, -1, -1};
int result = 0;
for (int i = 0; i < 4; i++) {
  result = ((result << 8) + b[i]);
}

In performing the bitwise operation, the value of the byte array element b[i] is promoted to an int by sign-extension. When a byte array element contains a negative value (for example, 0xff), the sign-extension propagates 1-bits into the upper 24 bits of the int. This behavior may be unexpected if the programmer is assuming that byte is an unsigned type. In this example, adding the promoted byte values to result fails to result in a packed integer representation of the bytes [[Findbugs 2008]].

Noncompliant Code Example

This noncompliant code example masks off the upper 24 bits of the promoted byte array element before performing the addition. The number of bits required to mask the sizes of byte and int are specified by the JLS. While this code calculates the correct result, it violates this guideline by combining bitwise and arithmetic operations on the same data.

byte[] b = new byte[] {-1, -1, -1, -1};
int result = 0;
for (int i = 0; i < 4; i++) {
  result = ((result << 8) + (b[i] & 0xff));
}

Compliant Solution

This compliant solution masks off the upper 24 bits of the promoted byte array element. The result is then combined with result using a logical OR operation.

byte[] b = new byte[] {-1, -1, -1, -1};
int result = 0;
for (int i = 0; i < 4; i++) {
  result = ((result << 8) | (b[i] & 0xff));
}

Exceptions

EX0: Bitwise operations may be used to construct constant expressions.

int limit = 1 << 17 - 1; // 2^17 - 1 = 131071

EX1: Data that is normally treated arithmetically may be treated with bitwise operations for the purpose of serialization or deserialization. This is often required for reading or writing the data from a file or network socket, It may also be used when reading or writing the data from a tightly packed data structure of bytes.

int value = /* interesting value */
Byte[] bytes = new Byte[4];
for (int i = 0; i < bytes.length; i++) {
  bytes[i] = value >> (i*8) & 0xFF;
}
/* bytes[] now has same bit representation as value  */

Risk Assessment

Performing bit manipulation and arithmetic operations on the same variable obscures the programmer's intentions and reduces readability. This in turn makes it more difficult for a security auditor or maintainer to determine which checks must be performed to eliminate security flaws and ensure data integrity.

Recommendation

Severity

Likelihood

Remediation Cost

Priority

Level

NUM02-J

medium

unlikely

medium

P4

L3

Related Guidelines

CERT C Secure Coding Standard: INT14-C. Avoid performing bitwise and arithmetic operations on the same data

CERT C++ Secure Coding Standard: INT14-CPP. Avoid performing bitwise and arithmetic operations on the same data

Bibliography

[[Steele 1977]]


INT13-C. Use bitwise operators only on unsigned operands      04. Integers (INT)      INT15-C. Use intmax_t or uintmax_t for formatted IO on programmer-defined integer types

  • No labels