Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Reverted from v. 126

Integer overflow is undefined behavior. This means that implementations have a great deal of latitude in how they deal with signed integer overflow. An implementation that defines signed integer types as being modulo, for example, need not detect integer overflow. Implementations may also trap on signed arithmetic overflows, or simply assume that overflows will never happen and generate object code accordingly (see MSC15-C. Do not depend on undefined behavior). For these reasons, it is important to ensure that operations on signed integers do not no result in signed overflow. Of particular importance, however, are operations on signed integer values that originate from untrusted sources and are used in any of the following ways:

...

This noncompliant code example may result in a signed integer overflow during the addition of the signed operands si1 and si2. If this behavior is unanticipated, it can lead to an exploitable vulnerability.

Code Block
bgColor#FFcccc

int si1, si2, sum;

/* Initialize si1 and si2 */

sum = si1 + si2;

...

This compliant solution tests the operands of the addition to ensure no overflow occurs, assuming two's complement representation.

Code Block
bgColor#ccccff

signed int si1, si2, sum;

/* Initialize si1 and si2 */

if ( ((si1^si2) 
   | (((si1^(~(si1^si2) 
     & (1 << (sizeof(int)*CHAR_BIT-1))))+si2)^si2)) >= 0) {
   /* handle error condition */
}
else {
  sum = si1 + si2;
}

...

This compliant solution tests the suspect addition operation to ensure no overflow occurs regardless of representation.

Code Block
bgColor#ccccff

signed int si1, si2, sum;

/* Initialize si1 and si2 */

if (((si1>0) && (si2>0) && (si1 > (INT_MAX-si2))) 
 || ((si1<0) && (si2<0) && (si1 < (INT_MIN-si2)))) {
   /* handle error condition */
}
else {
  sum = si1 + si2;
}

...

This noncompliant code example can result in a signed integer overflow during the subtraction of the signed operands si1 and si2. If this behavior is unanticipated, the resulting value may be used to allocate insufficient memory for a subsequent operation or in some other manner that can lead to an exploitable vulnerability.

Code Block
bgColor#FFcccc

signed int si1, si2, result;

/* Initialize si1 and si2 */

result = si1 - si2;

...

This compliant solution tests the operands of the subtraction to guarantee there is no possibility of signed overflow, presuming two's complement representation.

Code Block
bgColor#ccccff

signed int si1, si2, result;

/* Initialize si1 and si2 */

if (((si1^si2) 
  & (((si1 ^ ((si1^si2) 
    & (1 << (sizeof(int)*CHAR_BIT-1))))-si2)^si2)) < 0) {
  /* handle error condition */
}
else {
  result = si1 - si2;
}

...

This noncompliant code example can result in a signed integer overflow during the multiplication of the signed operands si1 and si2. If this behavior is unanticipated, the resulting value may be used to allocate insufficient memory for a subsequent operation or in some other manner that can lead to an exploitable vulnerability.

Code Block
bgColor#FFcccc

signed int si1, si2, result;

/* ... */

result = si1 * si2;

...

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
bgColor#ccccff

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) ) {
  /* handle error condition */
}
else {
  result = (int)tmp;
}

...

On systems where this relationship does not exist, the following compliant solution may be used to ensure signed overflow does not occur.

Code Block
bgColor#ccccff

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)) {
      /* handle error condition */
    }
  } /* end if si1 and si2 are positive */
  else { /* si1 positive, si2 non-positive */
    if (si2 < (INT_MIN / si1)) {
        /* handle 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)) {
      /* handle 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))) {
      /* handle error condition */
    }
  } /* end if si1 and si2 are non-positive */
} /* end if si1 is non-positive */

result = si1 * si2;

...

This noncompliant code example can result in a signed integer overflow during the division of the signed operands sl1 and sl2 or in a divide-by-zero error. The IA-32 architecture, for example, requires that both conditions result in a fault, which can easily result in a denial-of-service attack.

Code Block
bgColor#FFcccc

signed long sl1, sl2, result;

/* Initialize sl1 and sl2 */

result = sl1 / sl2;

...

This compliant solution guarantees there is no possibility of signed overflow or divide-by-zero errors.

Code Block
bgColorccccff

signed long sl1, sl2, result;

/* Initialize sl1 and sl2 */

if ( (sl2 == 0) || ( (sl1 == LONG_MIN) && (sl2 == -1) ) ) {
  /* handle error condition */
}
else {
  result = sl1 / sl2;
}

...

This noncompliant code example can result in a divide-by-zero error. Furthermore, many hardware platforms implement modulo as part of the division operator, which can overflow. Overflow can occur during a modulo operation when the dividend is equal to the minimum (negative) value for the signed integer type and the divisor is equal to — 1. This occurs in spite of the fact that the result of such a modulo operation should theoretically be 0.

Code Block
bgColor#FFcccc

signed long sl1, sl2, result;

result = sl1 % sl2;

...

This compliant solution tests the modulo operand to guarantee there is no possibility of a divide-by-zero error or an (internal) overflow error.

Code Block
bgColor#ccccff

signed long sl1, sl2, result;

/* Initialize sl1 and sl2 */

if ( (sl2 == 0 ) || ( (sl1 == LONG_MIN) && (sl2 == -1) ) ) {
  /* handle error condition */
}
else {
  result = sl1 % sl2;
}

...

This compliant solution is based on the fact that both the division and modulo operators truncate towards zero, as specified in a footnote in paragraph 6.5.5 of the C99 standard. This guarantees that:

Code Block

i % j

and

Code Block

i % -j

are always equivalent.

Furthermore, it guarantees that the minumum signed value modulo -1 yields 0.

Code Block
bgColor#ccccff

signed long sl1, sl2, result;

/* Initialize sl1 and sl2 */

if (sl2 == 0) {
  /* handle error condition */
}
else {
  if ((sl2 < 0) && (sl2 != LONG_MIN)) {
    sl2 = -sl2;
  }
  result = sl1 % sl2;
}

...

This noncompliant code example can result in a signed integer overflow during the unary negation of the signed operand si1.

Code Block
bgColor#FFcccc

signed int si1, result;

/* Initialize si1 */

result = -si1;

...

This compliant solution tests the suspect negation operation to guarantee there is no possibility of signed overflow.

Code Block
bgColorccccff

signed int si1, result;

/* Initialize si1 */

if (si1 == INT_MIN) {
  /* handle error condition */
}
else 
  result = -si1;
}

Anchor
Left Shift Operator
Left Shift Operator

...

This noncompliant code example can result in signed integer overflow.

Code Block
bgColor#FFcccc

int si1, si2, sresult;

/* Initialize si1 and si2 */

sresult = si1 << si2;

...

This compliant solution eliminates the possibility of overflow resulting from a left-shift operation.

Code Block
bgColor#ccccff

int si1, si2, sresult;

/* Initialize si1 and si2 */

if ( (si1 < 0) || (si2 < 0) ||
     (si2 >= sizeof(int)*CHAR_BIT) ||
     (si1 > (INT_MAX >> si2)) 
) {
  /* handle error condition */
}
else {
  sresult = si1 << si2;
}

...