Main Content

CWE Rule 190

Integer Overflow or Wraparound

Since R2024a

Description

Rule Description

The product performs a calculation that can produce an integer overflow or wraparound, when the logic assumes that the resulting value will always be larger than the original value. This can introduce other weaknesses when the calculation is used for resource management or execution control.

Polyspace Implementation

The rule checker checks for these issues:

  • Integer constant overflow

  • Integer conversion overflow

  • Integer overflow

  • Integer precision exceeded

  • Right operand of shift operation outside allowed bounds

  • Unsigned integer constant overflow

  • Unsigned integer conversion overflow

  • Unsigned integer overflow

  • Memory allocation with tainted size

Examples

expand all

Issue

This issue occurs in the following cases:

  • You assign a compile-time integer constant to a signed integer variable whose data type cannot accommodate the value.

    See Constant Overflows from Assignments.

  • You use an enum value that cannot be accommodated by the underlying type of the enum (and the underlying type is signed). For most C compilers, the default underlying type is signed int (based on the C standard).

    See Constant Overflows from enum Values.

  • You perform a binary operation involving two integer constants that results in an overflow, that is, a value outside the range allowed by the data type that the operation uses. A binary operation with integer constants uses the signed int data type (unless you use modifiers such as u or L).

    See Constant Overflows from Binary Operations.

An n-bit signed integer holds values in the range [-2n-1, 2n-1-1]. For instance, c is an 8-bit signed char variable that cannot hold the value 255.

signed char c = 255;

This defect checker depends on the following options:

You do not see the defect in these situations:

  • Creation of new constants from const variables (for specific compilers only).

    Different compilers might define compile-time constants differently. In the following code, c+1 is considered a compile-time constant by GCC compilers, but not by the standard C compiler:

    const int16_t c = 32767;
    int16_t y = c + 1;
    Whether you see a violation of this check on y might depend on your compiler.

  • Bitwise NOT operation.

    Polyspace® does not raise this violation when you perform a bitwise NOT operation.

Risk

The default behavior for constant overflows can vary between compilers and platforms. Retaining constant overflows can reduce the portability of your code.

Even if your compilers wraps around overflowing constants with a warning, the wrap-around behavior can be unintended and cause unexpected results.

Fix

Check if the constant value is what you intended. If the value is correct, use a different, possibly wider, data type for the variable.

Example — Constant Overflows from Assignments
#define MAX_UNSIGNED_CHAR 255  //Noncompliant
#define MAX_SIGNED_CHAR 127 //Noncompliant

void main() {
    char c1 = MAX_UNSIGNED_CHAR;
    char c2 = MAX_SIGNED_CHAR+1;
}

In this example, the defect appears on the macros because at least one use of the macro causes an overflow. To reproduce these defects, use a Target processor type (-target) where char is signed by default.

Correction — Use Different Data Type

One possible correction is to use a different data type for the variables that overflow.

#define MAX_UNSIGNED_CHAR 255 
#define MAX_SIGNED_CHAR 127

void main() {
    unsigned char c1 = MAX_UNSIGNED_CHAR;
    unsigned char c2 = MAX_SIGNED_CHAR+1;
}
Example — Constant Overflows from enum Values

enum {
  a=0x7fffffff,
  b, //Noncompliant
  c=0xffffffff //Noncompliant
} MyEnumA;

In this example, the enum has an underlying type int. The int type can accommodate values in the range [-231, 231-1]. However, the value of the enumerator b is 0x80000000 or 231 (one more than the previous value a). This value falls outside the allowed range of int.

The value of c, that is 0xffffffff or 232-1, is even larger and also causes an overflow.

To see this defect:

Example — Constant Overflows from Binary Operations
const unsigned int K_ATM_Label_Ram_init_value [] = {
     0x06 | ( 3 << 29) ,
     0x80 | ( 9 << 29) , //Noncompliant
     ( 2 << 31 )         , //Noncompliant
};

In this example, two of the shift operations result in values that cannot be accommodated by the signed int data type. The signed int data type can accommodate values in the range [-231, 231-1]. The operation:

  • 9 << 29 results in the value 232+536870912.

  • 2 << 31 results in the value 232.

Note that even though the result is assigned to an unsigned int variable, the overflow detection uses the underlying type of the binary operation, that is, signed int.

Issue

This issue occurs when converting an integer to a smaller integer type. If the variable does not have enough bytes to represent the original value, the conversion overflows.

The exact storage allocation for different floating point types depends on your processor. See Target processor type (-target).

Risk

Integer conversion overflows result in undefined behavior.

Fix

The fix depends on the root cause of the defect. Often the result details (or source code tooltips in Polyspace as You Code) show a sequence of events that led to the defect. You can implement the fix on any event in the sequence. If the result details do not show this event history, you can search for previous references of variables relevant to the defect using right-click options in the source code and find related events. See also Interpret Bug Finder Results in Polyspace Desktop User Interface or Interpret Bug Finder Results in Polyspace Access Web Interface (Polyspace Access).

You can fix the defect by:

  • Using a bigger data type for the result of the conversion so that all values can be accommodated.

  • Checking for values that lead to the overflow and performing appropriate error handling.

In general, avoid conversions to smaller integer types.

See examples of fixes below.

If you do not want to fix the issue, add comments to your result or code to avoid another review. See:

Extend Checker

A default Bug Finder analysis might not raise this defect when the input values are unknown and only a subset of inputs cause an issue. To check for defects caused by specific system input values, run a stricter Bug Finder analysis. See Extend Bug Finder Checkers to Find Defects from Specific System Input Values.

Example — Converting from int to char
char convert(void) {

    int num = 1000000;

    return (char)num; //Noncompliant
}

In the return statement, the integer variable num is converted to a char. However, an 8-bit or 16-bit character cannot represent 1000000 because it requires at least 20 bits. So the conversion operation overflows.

Correction — Change Conversion Type

One possible correction is to convert to a different integer type that can represent the entire number.

long convert(void) {

    int num = 1000000;

    return (long)num;
}
Issue

This issue occurs when an operation on integer variables results in values that cannot be represented by the data type that the operation uses. This data type depends on the operand types and determines the number of bytes allocated for storing the result, thus constraining the range of allowed values.

Note that:

  • The data type used to determine an overflow is based on the operand data types. If you then assign the result of an operation to another variable, a different checker, Integer conversion overflow, determines if the value assigned also overflows the variable assigned to. For instance, in an operation such as:

    res = x + y;
    This checker checks for an overflow based on the types of x and y, and not on the type of res. The checker for integer conversion overflows then checks for an overflow based on the type of res.

  • The two operands in a binary operation might undergo promotion before the operation occurs. See also Code Prover Assumptions About Implicit Data Type Conversions (Polyspace Code Prover).

The exact storage allocation for different data types depends on your processor. See Target processor type (-target).

Risk

Integer overflows on signed integers result in undefined behavior.

Fix

The fix depends on the root cause of the defect. Often the result details (or source code tooltips in Polyspace as You Code) show a sequence of events that led to the defect. You can implement the fix on any event in the sequence. If the result details do not show this event history, you can search for previous references of variables relevant to the defect using right-click options in the source code and find related events. See also Interpret Bug Finder Results in Polyspace Desktop User Interface or Interpret Bug Finder Results in Polyspace Access Web Interface (Polyspace Access).

You can fix the defect by:

  • Using a bigger data type for the result of the operation so that all values can be accommodated.

  • Checking for values that lead to the overflow and performing appropriate error handling.

To avoid overflows in general, try one of these techniques:

  • Keep integer variable values restricted to within half the range of signed integers.

  • In operations that might overflow, check for conditions that can lead to the overflow and implement wrap around or saturation behavior depending on how the result of the operation is used. The result then becomes predictable and can be safely used in subsequent computations.

See examples of fixes below.

If you do not want to fix the issue, add comments to your result or code to avoid another review. See:

Extend Checker

A default Bug Finder analysis might not raise this defect when the input values are unknown and only a subset of inputs cause an issue. To check for defects caused by specific system input values, run a stricter Bug Finder analysis. See Extend Bug Finder Checkers to Find Defects from Specific System Input Values.

Example — Addition of Maximum Integer
#include <limits.h>

int plusplus(void) {

    int var = INT_MAX;
    var++;              //Noncompliant
    return var;
}

In the third statement of this function, the variable var is increased by one. But the value of var is the maximum integer value, so an int cannot represent one plus the maximum integer value.

Correction — Different Storage Type

One possible correction is to change data types. Store the result of the operation in a larger data type (Note that on a 32-bit machine, int and long has the same size). In this example, on a 32-bit machine, by returning a long long instead of an int, the overflow error is fixed.

#include <limits.h>

long long plusplus(void) {

    long long lvar = INT_MAX;
    lvar++;
    return lvar;
}
Issue

This issue occurs when an integer expression uses the integer size in an operation that exceeds the integer precision. On some architectures, the size of an integer in memory can include sign and padding bits. On these architectures, the integer size is larger than the precision which is just the number of bits that represent the value of the integer.

Risk

Using the size of an integer in an operation on the integer precision can result in integer overflow, wrap around, or unexpected results. For instance, an unsigned integer can be stored in memory in 64 bits, but uses only 48 bits to represent its value. A 56 bits left-shift operation on this integer is undefined behavior.

Assuming that the size of an integer is equal to its precision can also result in program portability issues between different architectures.

Fix

Do not use the size of an integer instead of its precision. To determine the integer precision, implement a precision computation routine or use a builtin function such as __builtin_popcount().

Example — Using Size of unsigned int for Left Shift Operation
#include <limits.h>

unsigned int func(unsigned int exp)
{
    if (exp >= sizeof(unsigned int) * CHAR_BIT) {
        /* Handle error */
    }
    return 1U << exp; //Noncompliant
}

In this example, the function uses a left shift operation to return the value of 2 raised to the power of exp. The operation shifts the bits of 1U by exp positions to the left. The if statement ensures that the operation does not shift the bits by a number of positions exp greater than the size of an unsigned int. However, if unsigned int contains padding bits, the value returned by sizeof() is larger than the precision of unsigned int. As a result, some values of exp might be too large, and the shift operation might be undefined behavior.

Correction — Implement Function to Compute Precision of unsigned int

One possible correction is to implement a function popcount() that computes the precision of unsigned int by counting the number of set bits.

#include <stddef.h>
#include <stdint.h>
#include <limits.h>

size_t popcount(uintmax_t);
#define PRECISION(umax_value) popcount(umax_value)


unsigned int func(unsigned int exp)
{
    if (exp >= PRECISION(UINT_MAX)) {
        /* Handle error */
    }
    return 1 << exp;
}




size_t popcount(uintmax_t num)
{
    size_t precision = 0;
    while (num != 0) {
        if (num % 2 == 1) {
            precision++;
        }
        num >>= 1;
    }
    return precision;
} 
Issue

This issue occurs when a shift operation can result in values that cannot be represented by the result data type. The data type of a variable determines the number of bytes allocated for the variable storage and constrains the range of allowed values.

The exact storage allocation for different data types depends on your processor. See Target processor type (-target).

Risk

Shift operation overflows can result in undefined behavior.

Fix

The fix depends on the root cause of the defect. Often the result details (or source code tooltips in Polyspace as You Code) show a sequence of events that led to the defect. You can implement the fix on any event in the sequence. If the result details do not show this event history, you can search for previous references of variables relevant to the defect using right-click options in the source code and find related events. See also Interpret Bug Finder Results in Polyspace Desktop User Interface or Interpret Bug Finder Results in Polyspace Access Web Interface (Polyspace Access).

You can fix the defect by:

  • Using a bigger data type for the result of the shift operation so that all values can be accommodated.

  • Checking for values that lead to the overflow and performing appropriate error handling.

See examples of fixes below.

If you do not want to fix the issue, add comments to your result or code to avoid another review. See:

Extend Checker

A default Bug Finder analysis might not raise this defect when the input values are unknown and only a subset of inputs cause an issue. To check for defects caused by specific system input values, run a stricter Bug Finder analysis. See Extend Bug Finder Checkers to Find Defects from Specific System Input Values.

Example — Left Shift of Integer
int left_shift(void) {

    int foo = 33;
    return 1 << foo;  //Noncompliant 
}

In the return statement of this function, bit-wise shift operation is performed shifting 1 foo bits to the left. However, an int has only 32 bits, so the range of the shift must be between 0 and 31. Therefore, this shift operation causes an overflow.

Correction — Different storage type

One possible correction is to store the shift operation result in a larger data type. In this example, by returning a long long instead of an int, the overflow defect is fixed.

long long left_shift(void) {

    int foo = 33;
    return 1LL << foo; 
}
Issue

This issue occurs in the following cases:

  • You assign a compile-time constant to an unsigned integer variable whose data type cannot accommodate the value.

  • You use an enum value that cannot be accommodated by the underlying type of the enum (and the underlying type is unsigned).

An n-bit unsigned integer holds values in the range [0, 2n-1]. For instance, c is an 8-bit unsigned char variable that cannot hold the value 256.

unsigned char c = 256;

This defect checker depends on the following options:

You do not see the defect in these situations:

  • Creation of new constants from const variables (for specific compilers only).

    Different compilers might define compile-time constants differently. In the following code, c+1u is considered a compile time-constant by GCC compilers, but not by the standard C compiler:

    const uint16_t c = 0xffffu;
    uint16_t y = c + 1u;
    Whether you see a violation of this check on y might depend on your compiler.

  • Bitwise NOT operation.

    Polyspace does not raise this violation when you perform a bitwise NOT operation.

Risk

The C standard states that overflowing unsigned integers must be wrapped around (see, for instance, the C11 standard, section 6.2.5). However, the wrap-around behavior can be unintended and cause unexpected results.

Fix

Check if the constant value is what you intended. If the value is correct, use a wider data type for the variable.

Example — Overflows from Assignments
#define MAX_UNSIGNED_CHAR 255 //Noncompliant
#define MAX_UNSIGNED_SHORT 65535 //Noncompliant

void main() {
    unsigned char c1 = MAX_UNSIGNED_CHAR + 1;
    unsigned short c2 = MAX_UNSIGNED_SHORT + 1;
}

In this example, the defect appears on the macros because at least one use of the macro causes an overflow.

Correction — Use Wider Data Type

One possible correction is to use a wider data type for the variables that overflow.

#define MAX_UNSIGNED_CHAR 255
#define MAX_UNSIGNED_SHORT 65535

void main() {
    unsigned short c1 = MAX_UNSIGNED_CHAR + 1;
    unsigned int c2 = MAX_UNSIGNED_SHORT + 1;
}
Issue

This issue occurs when converting an unsigned integer to a smaller unsigned integer type. If the variable does not have enough bytes to represent the original constant, the conversion overflows.

The exact storage allocation for different floating point types depends on your processor. See Target processor type (-target).

Risk

Integer conversion overflows result in undefined behavior.

Fix

The fix depends on the root cause of the defect. Often the result details (or source code tooltips in Polyspace as You Code) show a sequence of events that led to the defect. You can implement the fix on any event in the sequence. If the result details do not show this event history, you can search for previous references of variables relevant to the defect using right-click options in the source code and find related events. See also Interpret Bug Finder Results in Polyspace Desktop User Interface or Interpret Bug Finder Results in Polyspace Access Web Interface (Polyspace Access).

You can fix the defect by:

  • Using a bigger data type for the result of the conversion so that all values can be accommodated.

  • Checking for values that lead to the overflow and performing appropriate error handling.

In general, avoid conversions to smaller integer types.

See examples of fixes below.

If you do not want to fix the issue, add comments to your result or code to avoid another review. See:

Extend Checker

A default Bug Finder analysis might not raise this defect when the input values are unknown and only a subset of inputs cause an issue. To check for defects caused by specific system input values, run a stricter Bug Finder analysis. See Extend Bug Finder Checkers to Find Defects from Specific System Input Values.

Example — Converting from int to char
unsigned char convert(void) {
    unsigned int unum = 1000000U;

    return (unsigned char)unum;   //Noncompliant
}

In the return statement, the unsigned integer variable unum is converted to an unsigned character type. However, the conversion overflows because 1000000 requires at least 20 bits. The C programming language standard does not view unsigned overflow as an error because the program automatically reduces the result by modulo the maximum value plus 1. In this example, unum is reduced by modulo 2^8 because a character data type can only represent 2^8-1.

Correction — Change Conversion Type

One possible correction is to convert to a different integer type that can represent the entire number. For example, long.

unsigned long convert(void) {
    unsigned int unum = 1000000U;

    return (unsigned long)unum;  
}
Issue

This issue occurs when an operation on unsigned integer variables can result in values that cannot be represented by the result data type. The data type of a variable determines the number of bytes allocated for the variable storage and constrains the range of allowed values.

The exact storage allocation for different floating point types depends on your processor. See Target processor type (-target).

Risk

The C11 standard states that unsigned integer overflows result in wrap-around behavior. However, a wrap around behavior might not always be desirable. For instance, if the result of a computation is used as an array size and the computation overflows, the array size is much smaller than expected.

Fix

The fix depends on the root cause of the defect. Often the result details (or source code tooltips in Polyspace as You Code) show a sequence of events that led to the defect. You can implement the fix on any event in the sequence. If the result details do not show this event history, you can search for previous references of variables relevant to the defect using right-click options in the source code and find related events. See also Interpret Bug Finder Results in Polyspace Desktop User Interface or Interpret Bug Finder Results in Polyspace Access Web Interface (Polyspace Access).

You can fix the defect by:

  • Using a bigger data type for the result of the operation so that all values can be accommodated.

  • Checking for values that lead to the overflow and performing appropriate error handling. In the error handling code, you can override the default wrap-around behavior for overflows and implement saturation behavior, for instance.

See examples of fixes below.

If you do not want to fix the issue, add comments to your result or code to avoid another review. See:

Extend Checker

A default Bug Finder analysis might not raise this defect when the input values are unknown and only a subset of inputs cause an issue. To check for defects caused by specific system input values, run a stricter Bug Finder analysis. See Extend Bug Finder Checkers to Find Defects from Specific System Input Values.

Example — Add One to Maximum Unsigned Integer
#include <limits.h>

unsigned int plusplus(void) {

    unsigned uvar = UINT_MAX;
    uvar++; //Noncompliant
    return uvar;
}

In the third statement of this function, the variable uvar is increased by 1. However, the value of uvar is the maximum unsigned integer value, so 1 plus the maximum integer value cannot be represented by an unsigned int. The C programming language standard does not view unsigned overflow as an error because the program automatically reduces the result by modulo the maximum value plus 1. In this example, uvar is reduced by modulo UINT_MAX. The result is uvar = 1.

Correction — Different Storage Type

One possible correction is to store the operation result in a larger data type. In this example, by returning an unsigned long long instead of an unsigned int, the overflow error is fixed.

#include <limits.h>

unsigned long long plusplus(void) {

    unsigned long long ullvar = UINT_MAX;
    ullvar++;
    return ullvar;
}
Issue

This issue occurs when a memory allocation function, such as calloc or malloc, uses a size argument from an unsecure source.

Uncontrolled memory allocation can cause your program to request too much system memory. This consequence can lead to a crash due to an out-of-memory condition, or assigning too many resources.

Fix

Before allocating memory, check the value of your arguments to check that they do not exceed the bounds.

Extend Checker

By default, Polyspace assumes that data from external sources are tainted. See Sources of Tainting in a Polyspace Analysis. To consider any data that does not originate in the current scope of Polyspace analysis as tainted, use the command line option -consider-analysis-perimeter-as-trust-boundary.

Example — Allocate Memory Using Input From User
#include<stdio.h>
#include <stdlib.h>

int* bug_taintedmemoryallocsize(void) {
    size_t size;
    scanf("%zu", &size);
    int* p = (int*)malloc(size);//Noncompliant
    return p;
}

In this example, malloc allocates size bytes of memory for the pointer p. The variable size comes from the user of the program. Its value is not checked, and it could be larger than the amount of available memory. If size is larger than the number of available bytes, your program could crash.

Correction — Different Storage Type

One possible correction is to store the operation result in a larger data type. In this example, by returning an unsigned long long instead of an unsigned int, the overflow error is fixed.

#include <limits.h>

unsigned long long plusplus(void) {

    unsigned long long ullvar = UINT_MAX;
    ullvar++;
    return ullvar;
}

Check Information

Category: Others

Version History

Introduced in R2024a