Bitwise operators include the complement operator ~
, bitwise shift operators >>
and <<
, bitwise AND operator &
, bitwise exclusive OR operator ^
, and bitwise inclusive OR operator |
. Bitwise operators should be used only with unsigned integer operands, as the results of some bitwise operations on signed integers are implementation-defined.
Noncompliant Code Example (Right Shift)
The right-shift operation may be implemented as either an arithmetic (signed) shift or a logical (unsigned) shift. If E1
in the expression E1 >> E2
has a signed type and a negative value, the resulting value is implementation-defined. Also, a bitwise shift can result in undefined behavior. (See INT34-C. Do not shift an expression by a negative number of bits or by greater than or equal to the number of bits that exist in the operand.)
This noncompliant code example can result in an error condition on implementations in which an arithmetic shift is performed, and the sign bit is propagated as the number is shifted [Dowd 2006]:
int rc = 0; int stringify = 0x80000000; char buf[sizeof("256")]; rc = snprintf(buf, sizeof(buf), "%u", stringify >> 24); if (rc == -1 || rc >= sizeof(buf)) { /* Handle error */ }
In this example, stringify >> 24
evaluates to 0xFFFFFF80
, or 4,294,967,168. When converted to a string, the resulting value "4294967168"
is too large to store in buf
and is truncated by snprintf()
.
If this code had been implemented using sprintf()
instead of snprintf()
, this noncompliant code example would have resulted in a buffer overflow.
Compliant Solution (Right Shift)
In this compliant solution, stringify
is declared as an unsigned
integer. The value of the result of the right-shift operation is the integral part of the quotient of stringify
/ 2 ^ 24
:
int rc = 0; unsigned int stringify = 0x80000000; char buf[sizeof("256")]; rc = snprintf(buf, sizeof(buf), "%u", stringify >> 24); if (rc == -1 || rc >= sizeof(buf)) { /* Handle error */ }
Also, consider using the sprintf_s()
function, defined in ISO/IEC TR 24731-1, instead of snprintf()
to provide some additional checks. (See STR07-C. Use the bounds-checking interfaces for string manipulation.)
Exceptions
INT13-EX1: When used as bit flags, it is acceptable to use preprocessor macros as arguments to the &
and |
operators even if the value is not explicitly declared as unsigned.
fd = open(file_name, UO_WRONLY | UO_CREAT | UO_EXCL | UO_TRUNC, 0600);
INT13-EX2: If the right-side operand to a shift operator is known at compile time, it is acceptable for the value to be represented with a signed type provided it is positive.
#define SHIFT 24 foo = 15u >> SHIFT;
Risk Assessment
Performing bitwise operations on signed numbers can lead to buffer overflows and the execution of arbitrary code by an attacker in some cases, unexpected or implementation-defined behavior in others.
Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
INT13-C | High | Unlikely | Medium | P6 | L2 |
Automated Detection
Tool | Version | Checker | Description |
---|---|---|---|
|
| Can detect violations of this rule. In particular, it flags bitwise operations that involved variables not declared with | |
1.2 | CC2.INT13 | Fully implemented | |
5.0 |
| Can detect violations of this recommendation with the CERT C Rule Pack | |
9.7.1 | 50 S | Fully implemented | |
PRQA QA-C | Unable to render {include} The included page could not be found. | 4532, 4533, 4534, 4543, 4544 | Fully implemented |
3.1.1 |
|
|
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
CERT C++ Coding Standard | INT13-CPP. Use bitwise operators only on unsigned operands |
ISO/IEC TR 24772:2013 | Bit Representations [STR] Arithmetic Wrap-around Error [FIF] Sign Extension Error [XZI] |
MITRE CWE | CWE-682, Incorrect calculation |
Bibliography
[Dowd 2006] | Chapter 6, "C Language Issues" |
[C99 Rationale 2003] | Subclause 6.5.7, "Bitwise Shift Operators" |