CERA2

Datasheetcera2 · embedded

Integer Overflow: Causes, Real-World Bugs and Prevention

Integer overflow happens when an arithmetic operation produces a value that the destination integer type cannot represent. A fixed-width register has no spare digit to fall back on, so the result wraps around, traps, or becomes undefined behavior, depending on the data type and the programming language. That small boundary error can reset a counter to zero, throw a clock back to 1901, or shrink a size calculation into an undersized allocation.

Why every fixed-width integer has a hard edge

In computer architecture, an integer occupies a fixed number of bits. An 8-bit register has 28, or 256, possible bit patterns; a 32-bit register has 232. More bits widen the range, but no finite register can hold every possible result.

Integer type Signed range Unsigned range
8-bit -128 to 127 0 to 255
16-bit -32,768 to 32,767 0 to 65,535
32-bit -2,147,483,648 to 2,147,483,647 0 to 4,294,967,295
64-bit -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 0 to 18,446,744,073,709,551,615

In C, the widths of int, long, and short depend on the platform. Board-level code that needs a known range should use the exact-width types from <stdint.h>, such as int16_t or uint32_t.

What happens when an integer crosses its limit?

Unsigned arithmetic in C is defined modulo 2n. When an 8-bit unsigned value at 255 is incremented, it wraps to 0. That wraparound is predictable, but not automatically correct: a byte counter that jumps back to zero can still break a protocol or a limit check.

#include <stdint.h>
#include <stdio.h>

int main(void) {
    uint8_t counter = 255;
    counter++;                 /* defined: wraps modulo 2^8 */
    printf("%u\n", counter);   /* prints 0 */
    return 0;
}

Signed arithmetic needs more care. In two’s complement, adding 1 to the signed 8-bit value 127 produces the bit pattern for -128. In C and C++, however, signed integer overflow is undefined behavior. The optimizer may assume it never happens and delete code that tries to detect it after the fact.

#include <limits.h>
#include <stdbool.h>

/* Unsafe: if a == INT_MAX, a + 1 is undefined behavior,
   and the optimizer may delete this check entirely. */
bool will_overflow_unsafe(int a) {
    return a + 1 < a;
}

/* Safe: test the operands before adding. */
bool add_would_overflow(int a, int b) {
    return (b > 0 && a > INT_MAX - b) ||
           (b < 0 && a < INT_MIN - b);
}

Other languages make different promises. C# raises System.OverflowException inside a checked context, and Ada raises Constraint_Error on signed overflow. Python integers simply grow until available memory runs out.

How two’s-complement hardware detects an arithmetic overflow

After an addition or subtraction, x86 processors set two status flags. The carry flag signals unsigned overflow. The overflow flag signals that a two’s-complement result has left the signed range. It is set when the carry into the sign bit differs from the carry out of it.

The signs give a simple rule: adding two positive signed values can never legitimately yield a negative result, and adding two negative values can never yield a positive one. An 8-bit signed result of -128 from 127 + 1 is therefore an overflow. When the operands have different signs, signed addition cannot overflow at all.

Where overflow begins: conversions, counters, and size calculations

Integer overflow can start with an incremented counter, a subtracted deadline, multiplied dimensions, a shift into the sign bit, or a wide value converted to a narrow type. In C, signed +, -, *, division, remainder, increment, decrement, compound assignments, and left shifts all require careful range reasoning.

Conversions are among the easiest failures to miss. Ariane 5 Flight 501 broke up 37 seconds after launch on June 4, 1996, when a 64-bit floating-point value was converted to a 16-bit signed integer and triggered an overflow exception. The code had been reused from Ariane 4 and did not account for Ariane 5’s higher horizontal velocity.

Long-running embedded systems hit the same limit without any conversion. The Boeing 787 had to be power-cycled at least every 248 days because a signed 32-bit counter in its generator control units, counting hundredths of a second, would otherwise overflow. The Year 2038 problem is another deadline: signed 32-bit Unix time reaches its maximum on January 19, 2038, at 03:14:07 UTC and then jumps back to December 13, 1901.

Even a view counter can run out of room. In December 2014, Psy’s “Gangnam Style” approached 2,147,483,647 views, the maximum of a signed 32-bit integer, and YouTube switched its counter to a 64-bit integer.

Prevent integer overflow before the operation runs

The safe C pattern checks inputs and bounds before the arithmetic runs. Never add first and hope to catch a bad signed result afterward.

  1. Choose the range deliberately. Use a 64-bit type where the domain needs it, but still prove that multiplications and conversions fit.
  2. Check the operands before signed addition or multiplication. For positive operands, test b != 0 && a > MAX / b before computing a * b.
  3. Use the checked compiler builtins where available. GCC and Clang provide __builtin_add_overflow and __builtin_mul_overflow. They return true when the exact result does not fit, so use the result only when the call returned false.
  4. Define the response: reject the input, report an error, widen the type, or use saturated arithmetic when clamping at the minimum or maximum value is what the system requires.
#include <stdio.h>

int main(void) {
    int a = 2147483647, b = 1, result;

    if (__builtin_add_overflow(a, b, &result)) {
        fprintf(stderr, "overflow: %d + %d does not fit in int\n", a, b);
        return 1;
    }
    printf("%d\n", result);
    return 0;
}

During testing, Clang’s -fsanitize=signed-integer-overflow reports signed overflow at runtime, and -fsanitize=unsigned-integer-overflow can expose unintended wraparound. As a project-wide policy, -fwrapv makes signed wraparound defined in GCC and Clang, while -ftrapv turns signed overflow into a runtime trap. Neither flag replaces input validation or a documented range.

Why an arithmetic bug can become a security vulnerability

Integer overflow is an arithmetic error; a buffer overflow is a memory error. They are different failure classes, but one can trigger the other. If a multiplication used for an allocation size wraps to a small number, the program allocates too little memory and then writes the full amount. The result is a heap buffer overflow that corrupts memory.

In OpenSSH 3.3, an overflow in nresp * sizeof(char*) produced a zero-byte allocation, and a following loop overwrote the heap. The CWE catalog classifies this integer-overflow-to-buffer-overflow chain under CWE-190 and CWE-680. Integer overflow ranked 12th in the 2021 CWE Top 25 Most Dangerous Software Weaknesses. Other consequences include data corruption, infinite loops, crashes, and wrong authorization decisions when a negative value slips past a check that only tests the maximum.

Common overflow myths that hide real defects

  • “Unsigned cannot overflow.” In C it never causes undefined behavior, but it still wraps around and can break application logic.
  • “Two’s complement makes signed C safe.” C23 requires two’s-complement representation, yet signed overflow remains undefined behavior.
  • “A 64-bit counter solves the design.” At best it postpones the limit; it does not validate conversions, allocation sizes, or mixed-width arithmetic.
  • “The compiler will catch it.” Compilers optimize on the assumption that signed overflow never occurs. Use explicit checks and sanitizers.

Frequently Asked Questions

What is overflow in computer architecture?

It is the condition in which a result does not fit the fixed number of bits of a register or integer data type. The hardware records carry or signed-overflow status, and software decides how to respond.

What causes integer overflow, and what are some examples?

Addition, subtraction, multiplication, left shifts, narrowing conversions, and time or counter calculations can exceed a type’s range. Ariane 5’s conversion to a 16-bit signed value, the Boeing 787 counter, and YouTube’s 32-bit view counter are documented examples.

How do you detect overflow in two’s complement?

For signed addition, look for two positive operands that yield a negative result, or two negative operands that yield a positive one. In hardware, the overflow flag is set when the carry into and out of the sign bit differ.

How should a program handle an overflow error?

Check before computing, or use a checked operation such as a compiler overflow builtin. Then reject the input, return an error, trap, switch to a wider type, or saturate only if clamping is the specified behavior.

What is the difference between integer overflow and buffer overflow?

Integer overflow exceeds an arithmetic range. A buffer overflow writes outside allocated memory. A wrapped allocation size can connect the two: too little memory is allocated, then too much data is written.

Index

CompactPCI: PCI in a Eurocard

By the mid-nineties the PC industry had a fast, cheap, well-supported bus, and the industrial world had mechanics that could survive a factory floor. CompactPCI, published in 1995,

VMEbus: the rack that outlived its industry

VMEbus was specified in 1981 around the Motorola 68000 and the Eurocard mechanics that European instrument makers already had on the shelf. Forty years later there are still

PC/104: stacking instead of a backplane

PC/104 solved a mechanical problem before it solved an electrical one. An industrial controller that has to survive vibration cannot rely on a card edge sitting in a