...
Code Block |
---|
|
int si_a;
int si_b;
int sum;
void func(void) {
/* Initialize si_a and si_b */
sum = si_a + si_b;
/* ... */
} |
Compliant Solution (Precondition Test, Two's Complement)
...
Code Block |
---|
|
#include <limits.h>
signed int si_a;
signed int si_b;
signed int sum;
void func(void) {
/* Initialize si_a, and si_b and sum*/
if ( ((si_a^si_b) | (((si_a^(~(si_a^si_b) & INT_MIN)) + si_b)^si_b)) >= 0) {
/* Handle error condition */
} else {
sum = si_a + si_b;
}
} |
This compliant solution works only on architectures that use two's complement representation. Although most modern platforms use two's complement representation, it is best not to introduce unnecessary platform dependencies. (See MSC14-C. Do not introduce unnecessary platform dependencies.) This solution can also be more expensive than a postcondition test, especially on RISC CPUs.
...
Code Block |
---|
|
#include <limits.h>
signed int si_a;
signed int si_b;
signed int sum;
/* Initializevoid (func) {
/* Initialize si_a, and si_b and sum */
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 {
sum = si_a + si_b;
}
} |
This solution is more readable but may be less efficient than the solution that is specific to two's complement representation.
...
Code Block |
---|
|
signed int si_a;
signed int si_b;
signed int result;
void func(void) {
/* Initialize si_a and si_b */
result = si_a - si_b;
/* ... */
} |
Compliant Solution (Two's Complement)
...
Code Block |
---|
|
#include <limits.h>
signed int si_a;
signed int si_b;
signed int result;
void func(void) {
/* Initialize si_a, and si_b and result */
if (((si_a^si_b)
& (((si_a ^ ((si_a^si_b)
& (1 << (sizeof(int) *CHAR_BIT -1)))) - si_b)^si_b)) < 0) {
/* Handle error condition */
}
else {
result = si_a - si_b;
}
/* ... */
} |
This compliant solution works only on architectures that use two's complement representation. Although most modern platforms use two's complement representation, it is best not to introduce unnecessary platform dependencies. (See MSC14-C. Do not introduce unnecessary platform dependencies.)
...
Code Block |
---|
|
#include <limits.h>
signed int si_a;
signed int si_b;
singed int result;
/* Initialize si_a andvoid func(void) {
/* Initialize si_a, si_b and result */
if ((si_b > 0 && si_a < INT_MIN + si_b) ||
(si_b < 0 && si_a > INT_MAX + si_b)) {
/* Handle error condition */
}
else {
result = si_a - si_b;
}
/* ... */
} |
Anchor |
---|
| Multiplication |
---|
| Multiplication |
---|
|
...
Code Block |
---|
|
signed int si_a;
signed int si_b;
signed int result;
void func(void) {
/* ... Initialize si_a and si_b */
result = si_a * si_b;
|
Compliant Solution
Compliant Solution
This compliant solution guarantees there is no possibility of signed overflow on systems where long long
is at least twice the size of int
:
Code Block |
---|
|
#include <assert.h>
signed int si_a;
signed int si_b;
signed int result;
void func(void) {
/* Initialize si_a, and si_b and result */
static_assert(
sizeof(long long) >= 2 * sizeof(int),
"Unable to detect overflow after multiplication"
);
signed long long tmp = (signed long long)si_a *
(signed long long)si_b;
/*
* If 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 compliant solution uses a static assertion to ensure that the overflow detection will succeed. See DCL03-C. Use a static assertion to test the value of a constant expression for a discussion of static assertions.
...
Code Block |
---|
|
signed int #include <limits.h>
signed int si_a;
signed int si_b;
signed int result;
void func(void) {
/* Initialize si_a, and si_b and result */
if (si_a > 0){ /* si_a is positive */
if (si_b > 0) { /* si_a and si_b are positive */
if (si_a > (INT_MAX / si_b)) {
/* Handle error condition */
}
}
/* End if si_a and si_b are positive */
} else { /* si_a positive, si_b nonpositive */
if (si_b < (INT_MIN / si_a)) {
/* Handle error condition */
}
} /* si_a positive, si_b nonpositive */
} else { /* End if si_a is positivenonpositive */
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 */
}
}
/* End if si_a is nonpositive, si_b is positive */
} 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 |
---|
|
signed long s_a;
signed long s_b;
signed long result;
void func(void) {
/* Initialize s_a and s_b */
result result = s_a / s_b;
/* ... */
} |
Compliant Solution
This compliant solution guarantees there is no possibility of signed overflow or divide-by-zero errors:
Code Block |
---|
|
#include <limits.h>
signed long s_a;
signed long s_b;
signed long result;
void func(void) {
/* Initialize s_a and, s_b and result */
if ( (s_b == 0) || ( (s_a == LONG_MIN) && (s_b == -1) ) ) {
/* Handle error condition */
}
else {
result = s_a / s_b;
}
/* ... */
} |
Modulo
The modulo operator provides the remainder when two operands of integer type are divided.
...
Code Block |
---|
|
signed long s_a;
signed long s_b;
signed long result;
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
.
...
Code Block |
---|
|
#include <limits.h>
signed long s_a;
signed long s_b;
signed long result;
void func(void) {
/* Initialize s_a and, s_b and result */
if ( (s_b == 0 ) || ( (s_a == LONG_MIN) && (s_b == -1) ) ) {
/* Handle error condition */
}
else {
result = s_a % s_b;
}
/* ... */
} |
Compliant Solution (Absolute Value)
...
Code Block |
---|
|
#include <limits.h>
signed long s_a;
signed long s_b;
signed long result;
void func(void) {
/* Initialize s_a, and s_b and result */
if (s_b == 0) {
/* Handle error condition */
}
else {
if ((s_b < 0) && (s_b != LONG_MIN)) {
s_b = -s_b;
}
result = s_a % s_b;
}
/* ... */
} |
Anchor |
---|
| Unary Negation |
---|
| Unary Negation |
---|
|
...
Code Block |
---|
|
signed long s_a;
signed long result;
void func(void) {
/* Initialize s_a */
result = -s_a;
/* ... */
} |
Compliant Solution
This compliant solution tests the suspect negation operation to guarantee there is no possibility of signed overflow:
Code Block |
---|
|
#include <limits.h>
signed long s_a;
signed long result;
void func(void) {
/* Initialize s_a and result*/
if (s_a == INT_MIN) {
/* Handle error condition */
}
else {
result = -s_a;
}
}
|
Anchor |
---|
| Left Shift Operator |
---|
| Left Shift Operator |
---|
|
...
Code Block |
---|
|
int si_a;
int si_b;
int sresult;
/* Initialize si_a and si_b */
sresult = si_a << si_b;
|
Compliant Solution
This compliant solution eliminates the possibility of overflow resulting from a left-shift operation:
Code Block |
---|
|
int si_a;
int si_b;
int sresult;
/* Initialize si_a and si_b */
if ( (si_a < 0) || (si_b < 0) ||
(si_b >= sizeof(int)*CHAR_BIT) ||
(si_a > (INT_MAX >> si_b))
void func(void) {
/* Handle error conditionInitialize si_a and si_b */
}
else {
sresult = si_a << si_b;
}
/* ... */
} |
Compliant Solution
This compliant solution eliminates the possibility of overflow resulting from a left-shift operation:
This solution is also compliant 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;
int si_a;
a;
void func(void) {
/* Initialize i, si_a */
atomic_fetch_add(&i, si_a);
/* ... */
} |
Compliant Solution
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:
Code Block |
---|
|
#include <limits.h>
#include <stdatomic.h>
atomic_int i;
int si_a;
void func(void) {
/* Initialize si_a, i */
int si_b = atomic_load(&i);
if (((si_b>0) && (si_a > (INT_MAX-si_b)))
|| ((si_b<0) && (si_a < (INT_MIN-si_b)))) {
/* Handle error condition */
}
else {
atomic_fetch_add(&i, si_a);
}
/* ... */
} |
Risk Assessment
Integer overflow can lead to buffer overflows and the execution of arbitrary code by an attacker.
...