...
For these reasons, it is important to ensure that operations on signed integers do no result in overflow. (See MSC15-C. Do not depend on undefined behavior.) Of particular importance are operations on signed integer values that originate from untrusted sources and are used in any of the following ways:
- as As an array index
- in In any pointer arithmetic
- as As a length or size of an object
- as As the bound of an array (for example, a loop counter)
- as As an argument to a memory allocation function
- in In security-critical code
Most integer operations can result in overflow if the resulting value cannot be represented by the underlying representation of the integer. The following table indicates which operators can result in overflow:
Operator | Overflow |
| Operator | Overflow |
| Operator | Overflow |
| Operator | Overflow |
---|---|---|---|---|---|---|---|---|---|---|
+yes | Yes |
| yesYes |
| yesYes |
| < | noNo | ||
yesYes |
| yesYes |
| >> | noNo |
| > | noNo | ||
yesYes |
| yesYes |
| & | noNo |
| >= | noNo | ||
yesYes |
| yesYes |
| | | noNo |
| <= | noNo | ||
yesYes |
| yesYes |
| ^ | noNo |
| == | noNo | ||
++ | yesYes |
| >>= | noNo |
| ~ | noNo |
| != | noNo |
-- | yesYes |
| &= | noNo |
| ! | noNo |
| && | noNo |
= | noNo |
| |= | noNo |
| un + | noNo |
| || | noNo |
yesYes |
| ^= | noNo |
| yesYes |
| ?: | noNo |
The following sections examine specific operations that are susceptible to integer overflow. When operating on small integer types (smaller than int
), integer promotions are applied. The usual arithmetic conversions may also be applied to (implicitly) convert operands to equivalent types before arithmetic operations are performed. Make sure you understand integer conversion rules before trying to implement secure arithmetic operations. (See INT02-C. Understand integer conversion rules.)
...
Code Block | ||||
---|---|---|---|---|
| ||||
signed int si1, si2, sum; /* Initialize si1 and si2 */ if ( ((si1^si2) | (((si1^(~(si1^si2) & INT_MIN)) + si2)^si2)) >= 0) { /* handleHandle error condition */ } else { sum = si1 + si2; } |
...
Code Block | ||||
---|---|---|---|---|
| ||||
signed int si1, si2, sum; /* Initialize si1 and si2 */ if (((si2>0) && (si1 > (INT_MAX-si2))) || ((si2<0) && (si1 < (INT_MIN-si2)))) { /* handleHandle error condition */ } else { sum = si1 + si2; } |
...
Code Block | ||||
---|---|---|---|---|
| ||||
signed int si1, si2, result; /* Initialize si1 and si2 */ if (((si1^si2) & (((si1 ^ ((si1^si2) & (1 << (sizeof(int)*CHAR_BIT-1))))-si2)^si2)) < 0) { /* handleHandle error condition */ } else { result = si1 - si2; } |
...
Code Block | ||||
---|---|---|---|---|
| ||||
signed int si1, si2, result; /* Initialize si1 and si2 */ if ((si2 > 0 && si1 < INT_MIN + si2) || (si2 < 0 && si1 > INT_MAX + si2)) { /* handleHandle error condition */ } else { result = si1 - si2; } |
...
Code Block | ||||
---|---|---|---|---|
| ||||
signed int si1, si2, result; /* Initialize si1 and si2 */ static_assert( sizeof(long long) >= 2 * sizeof(int), "Unable to detect overflow after multiplication" ); signed long long tmp = (signed long long)si1 * (signed long long)si2; /* * If the product cannot be represented as a 32-bit integer, * handle as an error condition. */ if ( (tmp > INT_MAX) || (tmp < INT_MIN) ) { /* handleHandle error condition */ } else { result = (int)tmp; } |
...
Code Block | ||||
---|---|---|---|---|
| ||||
signed int si1, si2, result; /* Initialize si1 and si2 */ if (si1 > 0){ /* si1 is positive */ if (si2 > 0) { /* si1 and si2 are positive */ if (si1 > (INT_MAX / si2)) { /* handleHandle error condition */ } } /* end if si1 and si2 are positive */ else { /* si1 positive, si2 non-positive */ if (si2 < (INT_MIN / si1)) { /* handleHandle error condition */ } } /* si1 positive, si2 non-positive */ } /* end if si1 is positive */ else { /* si1 is non-positive */ if (si2 > 0) { /* si1 is non-positive, si2 is positive */ if (si1 < (INT_MIN / si2)) { /* handleHandle error condition */ } } /* end if si1 is non-positive, si2 is positive */ else { /* si1 and si2 are non-positive */ if ( (si1 != 0) && (si2 < (INT_MAX / si1))) { /* handleHandle error condition */ } } /* end if si1 and si2 are non-positive */ } /* end if si1 is non-positive */ result = si1 * si2; |
...
Code Block | ||||
---|---|---|---|---|
| ||||
signed long sl1, sl2, result; /* Initialize sl1 and sl2 */ if ( (sl2 == 0) || ( (sl1 == LONG_MIN) && (sl2 == -1) ) ) { /* handleHandle error condition */ } else { result = sl1 / sl2; } |
...
Code Block | ||||
---|---|---|---|---|
| ||||
signed long sl1, sl2, result; /* Initialize sl1 and sl2 */ if ( (sl2 == 0 ) || ( (sl1 == LONG_MIN) && (sl2 == -1) ) ) { /* handleHandle error condition */ } else { result = sl1 % sl2; } |
...
Code Block | ||||
---|---|---|---|---|
| ||||
signed long sl1, sl2, result; /* Initialize sl1 and sl2 */ if (sl2 == 0) { /* handleHandle error condition */ } else { if ((sl2 < 0) && (sl2 != LONG_MIN)) { sl2 = -sl2; } result = sl1 % sl2; } |
...
Code Block | ||||
---|---|---|---|---|
| ||||
signed int si1, result; /* Initialize si1 */ if (si1 == INT_MIN) { /* handleHandle error condition */ } else result = -si1; } |
...
Code Block | ||||
---|---|---|---|---|
| ||||
int si1, si2, sresult; /* Initialize si1 and si2 */ if ( (si1 < 0) || (si2 < 0) || (si2 >= sizeof(int)*CHAR_BIT) || (si1 > (INT_MAX >> si2)) ) { /* handleHandle error condition */ } else { sresult = si1 << si2; } |
...
Code Block | ||||
---|---|---|---|---|
| ||||
atomic_int i; int si1; /* Initialize si1, i */ int si2 = atomic_load(&i); if (((si2>0) && (si1 > (INT_MAX-si2))) || ((si2<0) && (si1 < (INT_MIN-si2)))) { /* handleHandle error condition */ } else { atomic_fetch_add(&i, si1); } |
...