CertC-INT13¶
Use bitwise operators only on unsigned operands
Required inputs: IR
Bitwise operators include the complement operator
~, bitwise shift operators
>> and
<<, bitwise AND operator
&, bitwise exclusive OR operator
^, bitwise inclusive OR operator
| and compound assignment operators >>=, <<=, &=,
^= and |=. Bitwise operators should be used only with unsigned integer
operands, as the results of bitwise operations on signed integers are
implementation-defined.
The C11 standard, section 6.5, paragraph 4 [ ISO/IEC 9899:2011], states:
Some operators (the unary operator ~ , and the binary operators <<, >>, &, ^, and |, collectively described as bitwise operators) shall have operands that have integral type. These operators return values that depend on the internal representations of integers, and thus have implementation-defined and undefined aspects for signed types.
Furthermore, the bitwise shift operators << and
>> are undefined under many circumstances, and are
implementation-defined for signed integers for more circumstances; see rule
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 for more information.
Implementation details
The Microsoft C compiler documentation says that:
Bitwise operations on signed integers work the same as bitwise operations on unsigned integers.
On-line GCC documentation about the implementation of bitwise operations on signed integers says:
Bitwise operators act on the representation of the value including both the sign and value bits, where the sign bit is considered immediately above the highest-value value bit.
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-C-EX1: When used as bit flags, it is acceptable to use
preprocessor macros or enumeration constants 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-C-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 |
Related Guidelines
| SEI CERT C++ Coding Standard | VOID 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" |
Possible Messages
Key |
Text |
Severity |
Disabled |
|---|---|---|---|
bitop_on_enum |
Bitwise operator on enum underlying type |
None |
False |
bitop_on_signed |
Bitwise operator on signed underlying type |
None |
False |
Options¶
This rule shares the following common options: exclude_in_macros, exclude_messages_in_system_headers, excludes, extend_exclude_to_macro_invocations, includes, justification_checker, languages, post_processing, provider, report_at, severity
The following places define options that affect this rule: Stylechecks, Analysis-GlobalOptions
allow_shift_of_constant_if_sign_unchanged¶
allow_shift_of_constant_if_sign_unchanged : bool = False