Avoid performing bitwise and arithmetic operations on the same data. In particular, bitwise operations are frequently performed on arithmetic values as a form of premature optimizationInteger variables are frequently intended to represent either a numeric value or a bit collection. Numeric values must be exclusively operated on using arithmetic operations, whereas bit collections must be exclusively operated on using bitwise operations. Bitwise operators include the unary operator ~ and the binary operators <<
, >>
, >>>
, &
, ^, and |
.
Performing bitwise and arithmetic operations on the same data can obscure the purpose of the data stored in the variable and often indicates confusion regarding that purpose. Unfortunately, bitwise operations are frequently performed on arithmetic values as a form of premature optimization. Although such operations are valid and will compile, they can reduce code readability. Declaring a variable as containing a numeric value or a bitmap makes the programmer's intentions clearer and the code more maintainable.
Bitmapped types may be defined to further separate bit collections from numeric types. This may make it easier to verify that bitwise operations are only performed on variables that represent bitmaps.
Code Block |
---|
typedef uint32_t bitmap32_t;
bitmap32_t x = 0x000007f3;
x = (x << 2) | 3; /* shifts in two 1-bits from the right */
|
The typedef
name uintN_t
designates an unsigned integer type with width N
. Consequently, uint32_t
denotes an unsigned integer type with a width of exactly 32 bits. Bitmaps should be declared as unsigned. See recommendation INT13-C. Use bitwise operators only on unsigned operands.
.
Noncompliant Code Example (Left Shift)
Left- and right-shift operators are often employed to multiply or divide a number by a power of 2. However, using shift operators to represent multiplication or division is an optimization that renders the code less portable and less readable. Furthermore, most compilers routinely will optimize multiplications and divisions by constant powers of 2 with bit-shift operations, and they are more familiar with two. This approach compromises code readability and portability for the sake of often-illusory speed gains. The Java Virtual Machine (JVM) usually makes such optimizations automatically, and, unlike a programmer, the JVM can optimize for the implementation details of the current platform.
Noncompliant Code Example (Left Shift)
In this This noncompliant code example , includes both bit manipulation bitwise and arithmetic manipulation are performed on manipulations of the integer x
that conceptually contains a numeric value. The result is a ( prematurely ) optimized statement that assigns the value 5x + 1
to x
for implementations, where integers are represented as two's complement values, which is what the programmer intended to express.
Code Block | ||
---|---|---|
| ||
unsigned int x = 50; x += (x << 2) + 1; |
Noncompliant Code Example (Left Shift)
This noncompliant code example segregates arithmetic and bitwise operators by variables. The x
variable participates only in bitwise operations, and y
participates only in arithmetic operations.
Code Block | ||
---|---|---|
| ||
int x = 50; int y = x << 2; x += y + 1; |
Although this is a valid manipulation, the result of the shift depends on the underlying representation of the integer type and is consequently implementation defined. Additionally, the readability of the code is reducedThis example is noncompliant because the actual data has both bitwise and arithmetic operations performed on it, even though the operations are performed on different variables.
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.
Code Block | ||
---|---|---|
| ||
unsigned int x = 50;
x = 5 * x + 1;
|
A reviewer may could now recognize that the operation should also be checked for wrapping. This overflow. The need for an overflow check might not have been apparent in the original, noncompliant code example (see NUM00-J. Detect or prevent integer overflow for more information).
Noncompliant Code Example (Logical Right Shift)
In this noncompliant code example, the programmer prematurely optimizes code by replacing a division with a right shiftwishes to divide x
by 4. In a misguided attempt to optimize performance, the programmer uses a right-shift operation rather than a division operation.
Code Block | ||
---|---|---|
| ||
int x = -50; x >>>>>= 2; |
Although this code is likely to perform the division correctly, it is not guaranteed to. If x
has a signed type and a negative value, the operation is implementation defined and can be implemented as either an arithmetic shift or a logical shift. In the event of a logical shift, if the integer is represented in either one's complement or two's complement form, the most significant bit (which controls the sign for both representations) will be set to zero. This will cause a once negative number to become a possibly very large, positive number. For more details, see recommendation INT13-C. Use bitwise operators only on unsigned operands.
The >>>=
operator is a logical right shift; it fills the leftmost bits with zeroes, regardless of the number's original sign. After execution of this code sequence, x
contains a large positive number (specifically, 0x3FFFFFF3
). Using logical right shift for division produces an incorrect result when the dividend (x
in this example) contains a negative value.
Noncompliant Code Example (Arithmetic Right Shift)
In this noncompliant code example, the programmer attempts to correct the previous example by using an arithmetic right shift (the >>=
operator):
Code Block | ||
---|---|---|
| ||
int x = -50;
x >>= 2;
|
After this code sequence is run, x
contains the value -13
rather than the expected -12
. Arithmetic right shift truncates the resulting value toward negative infinity, whereas integer division truncates toward zeroFor example, if the internal representation of x
is 0xFFFF FFCE
(two's complement), an arithmetic shift results in 0xFFFF FFF3
(—13 in two's complement), while a logical shift results in 0x3FFF FFF3
(1,073,741,811 in two's complement).
Compliant Solution (Right Shift)
In this compliant solution, the right shift is replaced by division.
Code Block | ||
---|---|---|
| ||
int x = -50;
x /= 4;
|
The resulting value is now more likely to be consistent with the programmer's expectations.
Risk Assessment
Noncompliant Code Example
In this noncompliant code example, a programmer attempts to fetch four values from a byte array and pack them into the integer variable result
. The integer value in this example represents a bit collection, not a numeric value.
Code Block | ||
---|---|---|
| ||
// 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 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 might 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 Java Language Specification. Although this code calculates the correct result, it violates this rule by combining bitwise and arithmetic operations on the same data.
Code Block | ||
---|---|---|
| ||
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.
Code Block | ||
---|---|---|
| ||
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
NUM01-EX0: Bitwise operations may be used to construct constant expressions.
Code Block | ||
---|---|---|
| ||
int limit = (1 << 17) - 1; // 2^17 - 1 = 131071
|
Nevertheless, as a matter of style, it is preferable to replace such constant expressions with the equivalent hexadecimal constants.
Code Block | ||
---|---|---|
| ||
int limit = 0x1FFFF; // 2^17 - 1 = 131071
|
NUM01-J-EX1: Data that is normally treated arithmetically may be treated with bitwise operations for the purpose of serialization or deserialization. This alternative treatment is often required for reading or writing the data from a file or network socket. Bitwise operations are also permitted when reading or writing the data from a tightly packed data structure of bytes.
Code Block | ||
---|---|---|
| ||
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 bitwise Performing bit manipulation and arithmetic operations on the same variable obscures the programmer's intentions and reduces readability. This in turn makes it Consequently, it is more difficult for a security auditor or maintainer to determine which checks must be performed to eliminate security flaws and ensure data integrity. For instance, overflow checks are critical for numeric types that undergo arithmetic operations but less critical for numeric types that undergo bitwise operations.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|
NUM01- |
J |
Medium |
Unlikely |
Medium | P4 | L3 |
Automated Detection
Tool | Version | Checker | Description |
---|
Parasoft Jtest |
Fortify SCA
Section |
---|
V. 5.0 |
Section |
---|
can detect violations of this recommendation with the CERT C Rule Pack |
Section |
---|
Compass/ROSE |
Section |
---|
can detect violations of this recommendation. However, it can only detect those violations where both bitwise and arithmetic operators are used in the same expression |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
...
| CERT.NUM01.BADSHIFT CERT.NUM01.NCBAV | Avoid incorrect shift operations Do not perform bitwise and arithmetic operations on the same data |
Related Guidelines
INT14-C. Avoid performing bitwise and arithmetic operations on the same data | |
VOID INT14-CPP. Avoid performing bitwise and arithmetic operations on the same data |
ISO/IEC 9899:1999 Section 6.2.6.2, "Integer types"
ISO/IEC TR 24772 "STR Bit Representations"
MISRA Rules 6.4 and 6.5
Bibliography
Wiki Markup |
---|
\[[Steele 1977|AA. Bibliography#Steele 77]\] |
Bibliography
...
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