Skip to content

Integer Overflow and Integer Bugs

Integers in C have a fixed size (32 or 64 bits) and a limited range. When an operation produces a value outside that range, it “wraps around” (overflow/underflow), and if a signed number is treated as unsigned (or vice versa), its value changes drastically (signedness). These bugs are dangerous because those integers are often used as buffer sizes or indices: a wrong calculation leads to allocating too little memory, reading/writing out of bounds, or skipping a check — and from there to a classic overflow.

Integer overflow x + y exceeds the max -> wraps to a small/negative value
# in 32 bits: 0xFFFFFFFF + 1 = 0 (wraps to 0)
Integer underflow 0 - 1 in unsigned -> 0xFFFFFFFF (huge)
Signedness a negative int treated as unsigned -> giant number
# -1 (int) interpreted as unsigned = 4294967295
Truncation assigning an int (32) to a short (16) -> high bits lost
Multiplication len * sizeof(x) overflows -> allocates less than expected

The danger isn’t the integer itself but what it’s used for:

# 1) controlled allocation size -> heap/stack overflow
int n = user_input; // attacker enters a value that overflows
char *buf = malloc(n * 8); // n*8 overflows -> malloc allocates little
// then n elements are written -> heap overflow
# 2) skip a bounds check
if (index < MAX) { array[index] = x; } // if index is negative (signed) it passes the check
// but array[index] writes OUTSIDE the array (negative index)
# 3) underflow in a size -> huge copy
size_t len = header_len - 20; // if header_len < 20, len = huge -> memcpy overflow

The key pattern: an attacker-controlled integer feeding a malloc, a memcpy, an array index, or an if (x < limit) check.

# in reversing/code: look for arithmetic on sizes/indices
# before malloc, memcpy, read, loops
# bounds checks using signed where it should be unsigned
# fuzz with extreme values: 0, -1, 0xFFFFFFFF, INT_MAX, INT_MIN, large sizes
1. Find the controlled integer feeding a size/index/check
2. Choose a value that causes the desired effect:
- overflow -> small allocation -> heap/stack overflow (see pwn-stack/pwn-heap)
- signedness/negative -> skip the limit -> out-of-bounds write
- underflow -> giant size -> massive copy
3. Turn the resulting memory corruption into flow control (like a classic overflow)

The integer bug is often the first link that enables a classic stack or heap overflow.

  • Correct range checks: validate before operating; use unsigned types for sizes (size_t) and verify upper and lower bounds.
  • Overflow detection: safe functions (__builtin_add_overflow, C23’s ckd_add), -ftrapv, UBSan (UndefinedBehaviorSanitizer) in development.
  • Don’t compute sizes with arithmetic without checking overflow (if (n > MAX/8) error; before n*8).
  • Fuzzing with boundary values; code review focused on size arithmetic.
  • Identify controlled integers feeding sizes/indices/checks
  • Test boundary values (0, -1, 0xFFFFFFFF, INT_MAX/MIN)
  • Overflow in a size calculation → small allocation → overflow
  • Signedness/negative → skip a bounds check
  • Underflow → giant size → massive copy
  • Chain with stack/heap overflow (Stack Buffer Overflow/Heap Exploitation)
  • Turn into flow control
  • Blue: range validation, size_t, UBSan?