the integer-overflow-to-buffer-overflow chain
Imagine ordering boxes where each holds 100 items and the warehouse computes 'total = boxes times 100' on a counter that can only show three digits. Order 50 boxes and the true total is 5000, but the counter wraps and reports 000. The warehouse then ships a tiny container — and your 5000 items spill everywhere. The integer-overflow-to-buffer-overflow chain is this: a SIZE computation overflows and produces a too-small number, the program allocates that small buffer, then copies the real (large) amount of data into it.
Here is the precise version. Code very often computes an allocation size by multiplying or adding attacker-influenced numbers: malloc(count * size) or malloc(header_len + body_len). If count * size exceeds what the integer type can hold, it WRAPS. For UNSIGNED arithmetic this wrap is well-defined modular arithmetic (the result is reduced modulo 2 to the width), so for a 32-bit size_t, 0x10000 * 0x10000 wraps to 0, and malloc(0) returns a tiny or empty buffer. For SIGNED integers, overflow is undefined behavior — the compiler may assume it never happens and delete your 'if the size is too big' check entirely, which is even worse. Either way, the program now holds a buffer far smaller than the data it is about to write, and the subsequent memcpy or loop overflows it — turning an arithmetic slip into a heap or stack overflow with all the consequences of those.
It matters because the dangerous line of code is the innocent-looking multiplication, far from the copy that actually crashes, which makes these bugs hard to spot in review. The honest defenses: check for overflow BEFORE allocating (for example, reject if count > MAX / size), use calloc() which does the multiply-and-check for you, or use built-in checked-arithmetic helpers; and never rely on a post-hoc 'if (computed_size < needed)' test when the computation itself already wrapped.
uint32_t n = read_count(input); // attacker controls n = 0x40000000 char *buf = malloc(n * 4); // n*4 wraps 32-bit to 0 -> tiny buffer for (uint32_t i = 0; i < n; i++) // loop still runs n (huge) times buf[i] = next_byte(); // overflows the tiny buffer
The multiply wraps to a small size, but the loop bound n stays huge — the gap is the overflow.
Unsigned overflow is well-defined wraparound; signed overflow is undefined behavior, so the compiler may legally erase a 'too-big' guard you wrote — never conflate the two, and check before, not after.