...
Addition is between two operands of arithmetic type or between a pointer to an object type and an integer type. (See ARR37-C. Do not add or subtract an integer to a pointer to a non-array object and ARR38ARR30-C. Do not add or subtract an integer to a pointer if the resulting value does not refer to a valid array elementform or use out of bounds pointers or array subscripts.) Incrementing is equivalent to adding 1.
...
Code Block |
---|
|
void func(signed int si_a;
, signed int si_b;
int sum;
void func(void) {
/* Initialize si_a and si_b */
signed int sum = si_a + si_b;
/* ... */
} |
...
Code Block |
---|
|
#include <limits.h>
signedvoid f(signed int si_a;
, signed int si_b;
signed int sum;
void (func) {
/*signed Initialize si_a, si_b and sum */
int sum;
if (((si_b > 0) && (si_a > (INT_MAX - si_b))) ||
((si_b < 0) && (si_a < (INT_MIN - si_b)))) {
/* Handle error condition */
} else {
sum = si_a + si_b;
}
/* ... */
} |
...
Subtraction is between two operands of arithmetic type, two pointers to qualified or unqualified versions of compatible object types, or a pointer to an object type and an integer type. See ARR36-C. Do not subtract or compare two pointers that do not refer to the same array, ARR37-C. Do not add or subtract an integer to a pointer to a non-array object, and ARR38and ARR30-C. Do not add or subtract an integer to a pointer if the resulting value does not refer to a valid array elementform or use out of bounds pointers or array subscripts for information about pointer subtraction. Decrementing is equivalent to subtracting 1.
...
Code Block |
---|
|
signedvoid func(signed int si_a;
, signed int si_b;
signed int result;
void func(void) {
/*signed Initialize si_a and si_b */
result int diff = si_a - si_b;
/* ... */
} |
...
Code Block |
---|
|
#include <limits.h>
void func(signed int si_a;
, signed int si_b;
singed) {
signed int resultdiff;
void func(void) {
/* Initialize si_a, si_b and result */
if (( if ((si_b > 0 && si_a < INT_MIN + si_b) ||
(si_b < 0 && si_a > INT_MAX + si_b)) {
/* Handle error condition */
} else {
resultdiff = si_a - si_b;
}
/* ... */
} |
...
Code Block |
---|
|
void func(signed int si_a;
, signed int si_b;
signed int result;
void func(void) {
/* Initialize si_a and si_b */
signed int result = si_a * si_b;
/* ... */
} |
...
Code Block |
---|
|
#include <assert.h>
void func(signed int si_a;
, signed int si_b;) {
signed int result;
void func(void) {
/*signed Initialize si_a, si_b and result */long long tmp;
assert( UWIDTH( signed long long, ULLONG_MAX) >=
2 * UWIDTH( int, UINT_MAX));
signed long long
tmp = (signed long long)si_a *
(signed long long)si_b;
/*
* If (signed long long)si_b;
/*
* If the the product cannot be represented as a 32-bit integer,
* handle as an error condition.
*/
if ( (tmp > INT_MAX) || (tmp < INT_MIN) ) {
/* Handle error condition */
} else {
result = (int)tmp;
}
/* ... */
} |
The assertion fails if long long
has less than twice the width of int
. It relies on the UWIDTH()
macro, which is defined in INT19-C. Correctly compute integer widths.
On systems where this assertion would fail, the following compliant solution may be used to ensure signed overflow does not occur:
Code Block |
---|
|
#include <limits.h>
void func(signed int si_a;
, signed int si_b;) {
signed int result;
void func(void
if (si_a > 0) {
/* Initialize si_a, si_b and result */
if (si_a > 0) { /* sisi_a is positive */
if (si_b > 0) { /* si_a and si_b are positive */
if (si_a > (INT_MAX / si_b)) {
/* Handle error condition */
}
} else { /* si_a positive, si_b nonpositive */
if (si_b < (INT_MIN / si_a)) {
/* Handle error condition */
}
} /* si_a positive, si_b nonpositive */
} else { /* si_a is nonpositive */
if (si_b > 0) { /* si_a is nonpositive, si_b is positive */
if (si_a < (INT_MIN / si_b)) {
/* Handle error condition */
}
} else { /* si_a and si_b are nonpositive */
if ( (si_a != 0) && (si_b < (INT_MAX / si_a))) {
/* Handle error condition */
}
} /* End if si_a and si_b are nonpositive */
} /* End if si_a is nonpositive */
result = si_a * si_b;
} |
Division
...
Code Block |
---|
|
void func(signed long s_a;
, signed long s_b;) {
signed long result = s_a / s_b;
void func(void) {
/* Initialize s_a and s_b */
result = s_a / s_b;
/* ... */
} |
Compliant Solution
...
Code Block |
---|
|
#include <limits.h>
void func(signed long s_a;
, signed long s_b;) {
signed long result;
void func(void) {
/* Initialize s_a, s_b and result */
if ( (s_b == if ((s_b == 0) || ( (s_a == LONG_MIN) && (s_b == -1) ) ) {
/* Handle error condition */
} else {
result = s_a / s_b;
}
/* ... */
} |
...
Code Block |
---|
|
void func(signed long s_a;
, signed long s_b;) {
signed long result;
void func(void) {
/* Initialize = s_a and% s_b */
result = s_a % s_b;
;
/* ... */
} |
Implementation Details
On x86 platforms, the modulo operator for signed integers is implemented by the idiv
instruction code, along with the divide operator. Because INT_MIN / -1
overflows, this code will throw a floating-point exception on INT_MIN % -1
.
On MSVC++Microsoft Visual Studio 2012, taking the modulo of INT_MIN
by by −1
yields the value 0
. On GCC/Linux, taking the modulo of INT_MIN
by by −1
produces a floating-point exception. However, on GCC 4.2.4 and newer, with optimization enabled, taking the modulo of INT_MIN
by by −1
yields the value 0
.
Compliant Solution (Overflow Prevention)
...
Code Block |
---|
|
#include <limits.h>
void func(signed long s_a;
, signed long s_b;) {
signed long result;
void func(void) {
/* Initialize if ((s_b == 0) || ((s_a, s_b and result */
if ((s_b == 0) || ((s_a == LONG_MIN) && (s_b == -1))) {
/* Handle error condition */
} else {
result = s_a % s_b;
}
/* ... */
} |
...
are always equivalent.
FurthermoreHowever, it guarantees that the minimum signed value modulo −1 yields 0:modulo −1
results in undefined behavior because the minimum signed value divided by -1
is not representable.
Code Block |
---|
|
#include <limits.h>
void func(signed long s_a;
, signed long s_b;) {
signed long result;
void if func(void) {
/* Initialize s_b == 0 || (s_a, == sLONG_b and result */
if (MIN && s_b == 0-1)) {
/* Handle error condition */
} else {
if ((s_b < 0) && (s_b != LONG_MIN)) {
s_b = -s_b;
}
result = s_a % s_b;
}
/* ... */
} |
...
Code Block |
---|
|
void func(signed long s_a;) {
signed long result = -s_a;
void func(void) {
/* Initialize s_a */
result = -s_a;
/* ... */
} |
Compliant Solution
...
Code Block |
---|
|
#include <limits.h>
void func(signed long s_a;
signed long result;
void func(void) {
/* Initialize s_a and result */signed long result;
if (s_a == INT_MIN) {
/* Handle error condition */
} else {
result = -s_a;
}
/* ... */
}
|
...
Code Block |
---|
|
intvoid func(signed long si_a;
int, signed long si_b;
int sresult;
void func(void) {
/*signed Initialize si_a and si_b */
sresult long result = si_a << si_b;
/* ... */
} |
...
Code Block |
---|
|
#include <limits.h>
void func(signed long ssi_a;
, signed long si_b) {
signed long result;
void func(void) {
if ((si1si_a < 0) || (si2si_b < 0) ||
(si2si_b >= UWIDTH(signed long, ULONG_MAX)) ||
(si1si_a > (INT_MAX >> si2si_b))) {
/* Handle error condition */
} else {
sresultresult = si1 << si2;
}
/* ... */
}
|
Anchor |
---|
| Left Shift Operator |
---|
| Left Shift Operator |
---|
|
The UWIDTH()
macro provides the correct width for an unsigned integer type, and is defined in INT19-C. Correctly compute integer widths...see that rule for more information. This solution also complies with INT34-C. Do not shift a negative number of bits or more bits than exist in the operand.
...
Code Block |
---|
|
#include <stdatomic.h>
atomic_int i;
void func(int si_a;
void func(void) {
/* Initialize atomic_init(&i, si_a */42);
atomic_fetch_add(&i, si_a);
/* ... */
} |
...
This compliant solution tests the operands to guarantee there is no possibility of signed overflow. It loads the value stored in the atomic integer and tests for possible overflow before performing the addition:. However, this code contains a race condition where i
can be modified after the load, but prior to the atomic store. This solution is only compliant if i
is guaranteed to only be access by a single thread. See CON43-C. Do not assume that a group of calls to independently atomic methods is atomic for more information.
Code Block |
---|
Code Block |
---|
|
#include <limits.h>
#include <stdatomic.h>
atomic_int i;
void func(int si_a;
void func(void) {
/*int Initialize si_a, i */
int si_b = atomic_load(&i);
if (((si_b>0b > 0) && (si_a > (INT_MAX - si_b))) ||
((si_b<0b < 0) && (si_a < (INT_MIN - si_b)))) {
/* Handle error condition */
} else {
atomic_store(&i, si_a + si_b);
}
/* ... */
} |
...
Tool | Version | Checker | Description |
---|
Coverity | 6.5 | TAINTED_STATIC | Fully Implemented |
Fortify SCA | 5.0 | | Can detect violations of this rule with CERT C Rule Pack. Specifically, it checks to ensure that the operand of a unary negation is compared to the type's minimum value immediately before the operation |
LDRA tool suite | | 43 D 493 S 494 S | Partially implemented | PRQA QA-C | Include Page |
---|
PRQA_V | PRQA_V | 0278 0296 0297 2800 | Fully implemented |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
| Partially implemented |
PRQA QA-C | | 0278 0296 0297 2800 | Fully implemented |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
...
...