7 min read

Integer Overflow Explained: From an Odometer Rolling Over to a Rocket Self-Destructing

Integer Overflow Explained: From an Odometer Rolling Over to a Rocket Self-Destructing

This is the second post in the "Plain-Language Security" series. Last time we talked about Buffer Overflow (writing too much data, spilling past the space that was set aside for it); this time we're covering its cousin — Integer Overflow (a number running past its range). The fun part is that these two bugs often go hand in hand: the number goes wrong first, which makes the program set aside the wrong amount of space, and that in turn triggers exactly the kind of overflow from the last post. No background needed, as always. By the end you'll see how a single number that runs past its representable range can make a program allocate the wrong amount of space, send a rocket out of control, and even give birth to the classic "Nuclear Gandhi" urban legend.


The one-sentence version: a computer's numbers have a "digit limit"

Your phone's calculator can handle enormous numbers, so you might assume numbers inside a computer have no ceiling. But in many low-level programs, an integer lives in a "fixed-width slot" — just like the odometer in an old car that only has six digits and can display at most 999999.

So what happens when 999999 rolls another kilometre? This odometer has no seventh digit, so it flips back to 000000. When the result of a calculation runs past what the slot can represent, what happens next actually depends on the language and the type: it might wrap around like the odometer, it might throw an error outright, or it might produce "undefined behaviour" (where not even the programmer can guarantee what happens). In this post we'll start with the most intuitive case — the wrap-around.

Diagram 1: the odometer rolls over

Integer overflow: the odometer wraps aroundOnce a number is incremented past the slot's limit, it may not keep getting bigger — it wraps back to the minimum, just like an odometer jumping from 999999 back to 000000. At the limit Add 1 more 999999 All six digits full 000000 Flips to the minimum +1

An old car's odometer only has six digits, and once it rolls past 999999 there's no seventh digit to carry into, so it just starts counting from zero and flips back to 000000. When a number type inside a program does this kind of wrap-around, it's called Integer Overflow. On its own, "the number wraps around" sounds like nothing more than a calculation error — but as you're about to see, things spin out of control the moment the program trusts that wrong number to make a decision.

Diagram 2: how a miscalculated number becomes a security hole

This is where Integer Overflow and last post's Buffer Overflow go hand in hand. Before putting something into memory, many programs first work out "how much space do I need to set aside". If an overflow tampers with that calculation and produces an absurdly small number, the program sets aside a space that's too small — and then when you cram the real (very large) thing into it, it overflows.

The attack chain where integer overflow triggers a buffer overflowA user enters a huge number, the space calculation overflows into a tiny value, the program sets aside a space that's too small, and it gets overrun. (1) Enter a huge number Attacker feeds it on purpose (2) Calculation overflows Space computed as a tiny value (3) Space set aside is too small Program trusts that number (4) Overrun Spills over

Here's an everyday analogy: the program asks, "How many lunchboxes are you ordering? I'll set out tables based on the count." You enter an astronomical number, which makes it overflow when computing "how many tables total" and wrap around to 0, so it sets out just one small table — but the lunchboxes still arrive in the original astronomical quantity, the table can't hold them, and they all spill over. And that connects right back to last post's Buffer Overflow.

So Integer Overflow itself is often not the end goal, but the fuse: its job is to make the program "set aside the wrong amount of space," and the overflow that does the real damage is the next step it ignites. But one caveat — this is the most classic attack chain, but not the only outcome. Integer overflow can also directly distort a monetary calculation, an array index, a permission check, or a loop count, each of which can cause trouble entirely on its own.

The other direction: Integer Underflow

Wrap-around doesn't only happen going up — it happens going down too. There's a kind of slot that only stores 0 and positive numbers (called an "unsigned integer"). When an unsigned integer is 0 and you subtract 1, the result falls below the range it can represent. If the language or the arithmetic mode uses wrap-around rules, it becomes the largest value it can represent; for example, an 8-bit unsigned integer wraps from 0 to 255. This direction is called Integer Underflow.

Integer underflow and the Nuclear Gandhi legendUsing a wrap-around 8-bit unsigned integer as an example, subtracting 1 from 0 wraps down to the maximum value, 255. Unsigned integer at 0 Subtract 1 more 0 255 -1 A classic urban legend: Nuclear Gandhi In the game Civilization, Gandhi's aggression is subtracted until it wraps to the maximum, turning the master of peace into a nuke-happy warmonger.

This underflow has an incredibly famous urban legend attached to it: in the game Civilization, Gandhi's "aggression" value was originally set to the lowest possible 1, and when the system "subtracts 2" it becomes -1 — but that unsigned slot can't store negatives, so it wraps down to 255, instantly turning peaceful Gandhi into the most warlike, most nuke-happy maniac on the board. It has to be stressed that this story was later debunked by the developer himself and is in fact fictional, but it demonstrates underflow so perfectly that it long ago became a classic teaching example in engineering circles.

(Technically there's a third case too: in an environment that explicitly uses two's-complement wrap-around rules, a "signed integer" that can store negatives may, when you add 1 to its maximum positive value, flip to the minimum negative value — "add a positive number, and the result somehow goes negative"; but different languages and settings handle this differently.)

A real accident: the Ariane 5 rocket

This isn't just textbook theory. In the chain of events behind the 1996 Ariane 5 failure, the inertial reference system tried to convert a 64-bit floating-point value into a 16-bit signed integer. The value exceeded the representable range, and the unhandled exception caused both inertial reference systems to shut down one after the other. The rocket lost guidance roughly 37 seconds after the main engine ignition sequence began — about 30 seconds after lift-off — then abruptly yawed and broke apart, after which the self-destruct mechanism was triggered.

Note the detail of this case — it was not a silent odometer-style wrap-around, but a different outcome in which a number running past its range triggered an exception that brought the whole system down (echoing what we said earlier about "what happens next depends on the language and the design"). The accident destroyed the rocket along with four Cluster science satellites, and it became one of the most frequently cited software bugs in history.

How do modern programs guard against it?

Just like last time, modern tools and languages have long had defences ready. The focus of Integer Overflow defence is to "catch it before the calculation goes wrong":

Three ways to prevent integer overflowSet a sensible input range, use checked arithmetic, and check before converting types. Limit the input range Block unreasonable huge/tiny values first Use checked calculations checked arithmetic: report on overflow, don't just compute Check before converting When narrowing a type or converting, confirm the value is in range

Let's be precise about "just switch languages and you're fine," and not get overly optimistic. In Rust, dev mode panics and aborts on overflow by default, but release mode wraps around by default unless you enable checks separately; it also provides different strategies — checked_*, wrapping_*, saturating_* — so you can explicitly pick the behaviour you want. Python's integers really are arbitrary-precision and can grow very large, but they're still bounded by memory, and the moment you convert one into a fixed-width type (say, writing it into some binary format), it can go wrong all the same. So "use a bigger slot" only delays overflow; it can't guarantee it never wraps around — the real key, always, is "don't let a miscalculated number be silently trusted downstream."

Wrapping up

String the two posts together and one classic memory-corruption script is complete:

The attacker feeds in a number that's out of range -> the program overflows when computing "how much space to set aside" and wraps it to a small number -> it sets aside a space that's too small -> the real data gets crammed in and spills over (Buffer Overflow) -> critical data gets overwritten and the program is taken over.

Integer Overflow teaches us something counterintuitive: the fixed-width integers used by many low-level programs all have a representation ceiling. They live in slots of a finite size, and going out of range causes problems — it might wrap around, it might throw an error, it might set off an even worse chain reaction. And the moment any piece of code "trusts that wrong number without a shred of doubt," the gap is wide open.

Next time, we'll step into another family of memory bugs — not "writing too much into a space," and not "a number running past its range," but "handing something back, then quietly grabbing it and using it again": Use After Free. Same everyday analogies, same diagrams. Stay tuned.