Integer Error – “You can’t count that high” – CS2


Background

Summary:

Integer values that are too large or too small may fall outside the allowable bounds for their data type, leading to unpredictable problems that can both reduce the robustness of your code and lead to potential security problems.

Can't Sleep

Description:

Declaring a variable as type int allocates a fixed amount of space in memory. Most languages include several integer types, including short, int, long, etc. , to allow for less or more storage. The amount of space allocated limits the range of values that can be stored. For example, a 32-bit int variable can hold values from -231 through 231-1.

Operations that result in values outside of this range can lead to a variety of problems, which apply to all data types that store integer variables, including int, short, and long.

  • Integer Overflow: Mathematical operations can increase integer values above the maximum or decrease them below the minimum allowed values. For instance, if i = INT_MAX , the increment operator i++ will cause an overflow and the resulting value will be the smallest possible integer value INT_MIN. Addition, subtraction, multiplication, and even division can cause overflow problems.
  • Sign Errors: C++ has both signed and unsigned integer types. Signed variables can go from a large negative value to a large positive value, while unsigned variables can only store non-negative values.  Problems can arise when converting from a signed to an unsigned variable. For example, if you have a negative signed value (short i = -32767), and you were to assign that value to an unsigned variable (unsigned short u = i), the internal representation of the number is unchanged, but the resulting value is interpreted as being unsigned, leading to an undesired result (u=32769).
  • Truncation: If an integer is converted from a larger type to a smaller type (say, from a long to a short), the value will be truncated if it is outside the range of the smaller type: data that can’t fit will simply be thrown out. For example, if you have a long variable that has a value that is greater than the largest value that can be stored in a short (long l=32800), assigning the long to a short (short s = (short)l;) will cause a truncation error (s=-32736).

Risk – How can it happen?

Integer variables are often used to indicate the number of items that must be stored in an array or other fixed-size buffer. If a variable with an overflow is used for this purpose, the resulting buffer might be too small for the data that will be copied into it. This can cause your program to crash, lead to incorrect behavior, or open security vulnerabilities.

Example of occurrence:

1. On December 25, 2004, Comair airlines was forced to ground 1,100 flights after its flight crew scheduling software crashed. The software used a 16-bit integer (max 32,768) to store the number of crew changes. That number was exceeded due to bad weather that month which led to numerous crew reassignments.

2. Many Unix operating systems store time values in 32-bit signed (positive or negative) integers, counting the number of seconds since midnight on January 1, 1970. On Tuesday, January 19, 2038, this value will overflow, becoming a negative number. Although the impact of this problem in 2038 is not yet known, there are concerns that software that projects out to future dates – including tools for mortgage payment and retirement fund distribution – might face problems long before then. Source: Year 2038 Problem” http://en.wikipedia.org/wiki/Year_2038_problem

Code Responsibly – how to avoid an integer error?

  1. Know your limits: Familiarize yourself with the ranges available for each data type. Since the size of C++ data types is compiler and machine dependent, it is a good idea to run this sample program to show you the limits of each variable type.
  2. Choose your data types carefully: Many programming languages include multiple data types for storing integer values. If you have any concerns about the integer values that you will be using, learn about the options available in the language you are using, and choose integer types that are large enough to hold the values you will be using. One useful strategy for reducing integer errors is to declare any variable that is used to represent the size of an object, including integer values used as sizes, indices, loop counters, and lengths, as size_t. The size_t type is the unsigned integer type. If your variable will hold only positive values, declare as an unsigned int. If there’s any doubt at all as to whether the variable will have values that are too large for a short, use an int. If an int might be too small, use a long.
  3. Validate your input: Check input for ranges and reasonableness before conducting operations (more on this in future modules).
  4. Check for possible overflows: Always check results of arithmetic operations or parsing of strings to integers, to be sure that an overflow has not occurred. The result of multiplying two positive integers should be at least as big as both of those integers. If you find a result that overflows, you can take appropriate action before the result is used. Imagine you were adding two positive integers. Instead of writing:
     int sum = someInteger + someOtherInteger;

    You might try this instead:

            if (((someInteger >0) && (someOtherInteger >0) && (some Integer> (INT_MAX-someOtherInteger))) ||
                ((someInteger <0) && (someOtherInteger <0) && (someInteger < (INT_MIN-someOtherInteger))))
                            ... throw an exception to handle the problem
            else   //  no exception, so no overflow.
                             int sum = someInteger+someOtherInteger;
    

    This won't completely solve the problem – you'll need to recover from the exception.  As these tests can become fairly complex[1], you should be careful when relying upon manual checks for preventing integer overflow.

  5. Use compiler checks: Many compilers include options that can be used to check for possible integer overflows.  Read the documentation for your compiler and use these functions whenever possible.
  6. Use libraries that will help you avoid errors: C++ programmers might use the SafeInt class, which tests for errors before conducting operations. C programmers can use IntegerLib.


[1] See https://www.securecoding.cert.org/confluence/display/cplusplus/INT32-CPP.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow for examples of solutions for other operations.

Laboratory Assignment

Program 1

We'd like to write a program that will project the growth of a University's student population over the next 10 years. The following program asks the user to provide the current population and the rate of growth in percentages. As we assume that we can't grow by a fractional number of people in any given year, the growth is calculated as an integer.

#include <iostream>
using namespace std;

int main() {

  short pop;
  short growth;

  cout << "What is the current population? ";
  cin >> pop;
  cout << "What is the rate of growth? (e.g., for 10% enter 10)";
  cin >> growth;

  float growthRate= static_cast(growth)/100;
  cout << growthRate << endl;

  cout << "Year\tGrowth\tNew Population" << endl;

  for (size_t i =1; i <=10; i++) {
    short increase = static_cast(pop*growthRate);
    short newpop = pop +increase;

    cout << i << "\t" << increase << "\t" << newpop << endl;
    pop = newpop;
  }
  cout << "Final population is " << pop << endl;
}

Lab Questions:

  1. Type* the program and Compile. What happens if you start with a population of 10,000 and a 10% growth rate? How about 20,000?   Find two combinations of starting populations and growth rates that lead to overflows, and two that do not.
  2. Does a short seem like a good choice of data type for this program? Why or why not?
  3. Complete the security checklist for the program. Submit marked program and completed checklist.
  4. Write a corrected version of this program that uses appropriate data types that will make this program run correctly for calculating population growths for any university and any country in the world.


*Copying and pasting programs may result in syntax errors and other inconsistencies. It is recommended you type each program.


Security Checklist

Security Checklist

Vulnerability: Integer Errors Course: CS2
Check each line of code Completed
1. Underline each occurrence of an integer variable.
For each underlined variable:
2. Mark with a V any input operations that assign values to the variable.
3. Mark with a V any mathematical operations involving the variable.
4. Mark with a V any assignments made to the variable.
Shaded areas indicate vulnerabilities!
 

If this group reaches 4,294,967,296

Discussion Questions

  1. Click on the image on the right and explain the concept behind the group. Do you think it is likely that the group might cause an overflow?
  2. What dangers do integer overflows present?
  3. Discuss the implications of positive integer errors for array indices.
  4. Explore how division might cause integer overflows (hint: you should look at sources on the web for the answer)

Further Work (optional - check with your instructor if you need to answer the following questions)

  1. Write a version of program 1 that uses still uses short variables to store results and appropriate error and result handling to respond to errors. You may use the technique of storing values in temporary variables before assigning them to the short variables.
  2. Name three things you might do in your next program to prevent an integer error from occurring.
 
Copyright © Towson University