Back to Blog
high SEVERITY8 min read

Integer Overflow in malloc: How a Silent Bug Becomes a Heap Overflow

A high-severity integer overflow vulnerability was discovered and fixed in `src/coredump/_UCD_create.c`, where arithmetic multiplication used to compute a memory allocation size lacked overflow protection. If the multiplication wrapped around, an undersized buffer would be allocated, opening the door to a heap overflow attack. This fix closes a subtle but dangerous code path that could lead to memory corruption and potential code execution.

O
By orbisai0security
May 15, 2026

Integer Overflow in malloc: How a Silent Bug Becomes a Heap Overflow

Introduction

Some of the most dangerous security vulnerabilities don't announce themselves with loud crashes or obvious errors. Instead, they hide in plain sight — tucked inside a single arithmetic expression that looks completely harmless at first glance. Integer overflow vulnerabilities in memory allocation are exactly this kind of silent killer.

This post covers a high-severity integer overflow vulnerability found and fixed in src/coredump/_UCD_create.c, a C source file responsible for creating core dump analysis contexts. The bug was caught by a Semgrep static analysis rule (utils.custom.integer-overflow-malloc) and has since been patched.

If you write C or C++, or if you maintain any codebase that performs manual memory management, this is a vulnerability class you absolutely need to understand.


The Vulnerability Explained

What Is an Integer Overflow in malloc?

In C, when you allocate memory dynamically, you typically compute the size of the buffer you need and pass it to malloc() (or a similar allocator). A common pattern looks like this:

size_t count = get_item_count();
void *buf = malloc(count * sizeof(some_struct));

This looks reasonable. But here's the problem: count * sizeof(some_struct) is just arithmetic on integers. If count is large enough, the multiplication can overflow — wrapping around to a small number due to the fixed width of integer types in C.

For example, on a 32-bit or even 64-bit system:

size_t count = 0x40000001; // A large attacker-controlled value
size_t size  = count * 4;  // Wraps around! Result: 4 (not 4GB)

void *buf = malloc(4);     // Only 4 bytes allocated!
// But code proceeds to write count * 4 bytes into buf...
// → Heap overflow!

The allocator happily returns a tiny buffer, but the rest of the code assumes it's large enough to hold all the data. Writes beyond the buffer's end corrupt adjacent heap memory.

The Vulnerable Code Pattern

In src/coredump/_UCD_create.c at line 124, arithmetic multiplication was used to compute an allocation size without any overflow check:

// VULNERABLE: No overflow check before multiplication
size_t alloc_size = n_threads * sizeof(coredump_thread_t);
threads = malloc(alloc_size);

If n_threads is attacker-influenced (e.g., read from a malformed core dump file), a crafted value could cause the multiplication to wrap, resulting in a drastically undersized allocation.

How Could This Be Exploited?

Here's a realistic attack scenario:

  1. Attacker crafts a malicious core dump file with a manipulated thread count field — say, n_threads = 0x20000000 (536 million).
  2. The vulnerable code computes: 0x20000000 * 8 = 0x100000000, which on a 32-bit size_t wraps to 0. On a 64-bit system with smaller struct sizes, similar wraps are achievable.
  3. malloc(0) or malloc(small_number) succeeds, returning a tiny (or implementation-defined) buffer.
  4. The code then iterates over all n_threads entries, writing structured data into what it believes is a large buffer — but is actually tiny.
  5. Heap memory is corrupted, potentially overwriting heap metadata, function pointers, or other sensitive allocations.
  6. With enough control, an attacker may achieve arbitrary code execution.

Real-World Impact

Impact Area Description
Confidentiality Heap data from adjacent allocations may be leaked
Integrity Heap metadata and program data can be corrupted
Availability Application crash (denial of service)
Code Execution In sophisticated exploits, arbitrary code execution is possible

This vulnerability is particularly dangerous in tools that process untrusted input files — like core dump analyzers, which by their very nature consume externally-supplied binary data.


The Fix

What Changed?

The fix introduces an overflow check before the multiplication is used to compute the allocation size. The corrected pattern validates that the multiplication won't exceed the maximum representable value before proceeding.

Here's the general structure of a safe fix:

// SAFE: Check for overflow before multiplying
if (n_threads > SIZE_MAX / sizeof(coredump_thread_t)) {
    // Handle error: would overflow
    return NULL;
}

size_t alloc_size = n_threads * sizeof(coredump_thread_t);
threads = malloc(alloc_size);
if (threads == NULL) {
    // Handle allocation failure
    return NULL;
}

Why This Works

The key insight is the pre-division check:

if (n_threads > SIZE_MAX / sizeof(coredump_thread_t))

By dividing SIZE_MAX by the element size first, we compute the maximum safe value of n_threads. If n_threads exceeds this threshold, we know the multiplication would overflow — and we bail out before any damage is done.

This approach:
- ✅ Works entirely with integer arithmetic (no floating point needed)
- ✅ Is portable across 32-bit and 64-bit platforms
- ✅ Handles edge cases like sizeof() == 0 (though that's rare in practice)
- ✅ Adds negligible performance overhead

Alternative: Use calloc()

Another clean approach is to use calloc() instead of malloc() for array allocations:

// calloc performs the overflow check internally (on most implementations)
threads = calloc(n_threads, sizeof(coredump_thread_t));

calloc(nmemb, size) takes the count and element size as separate arguments, allowing the implementation to perform its own overflow check. It also zero-initializes the memory, which can prevent some classes of uninitialized-read bugs. However, relying solely on calloc without understanding your platform's guarantees is not a substitute for explicit validation of untrusted input values.


Prevention & Best Practices

1. Always Validate Sizes Before Allocation

Never trust externally-supplied size values directly. Validate bounds before use:

#define MAX_REASONABLE_THREADS 65536

if (n_threads == 0 || n_threads > MAX_REASONABLE_THREADS) {
    return -EINVAL;
}

2. Use Safe Multiplication Helpers

Consider wrapping your size calculations in a helper:

#include <stdint.h>

static inline int safe_mul_size(size_t a, size_t b, size_t *result) {
    if (b != 0 && a > SIZE_MAX / b) {
        return -1; // Would overflow
    }
    *result = a * b;
    return 0;
}

// Usage:
size_t alloc_size;
if (safe_mul_size(n_threads, sizeof(coredump_thread_t), &alloc_size) != 0) {
    return -EOVERFLOW;
}
void *buf = malloc(alloc_size);

3. Leverage Static Analysis Tools

The vulnerability in this case was caught by Semgrep with a custom rule targeting unsafe multiplication in allocation contexts. Add similar tools to your CI pipeline:

Tool What It Catches
Semgrep Custom rules for unsafe allocation patterns
Coverity Integer overflow, buffer overflows
AddressSanitizer (ASan) Runtime heap overflow detection
UBSan Undefined behavior including integer overflow
CodeQL Taint analysis from input to allocation

Run these tools on every pull request — don't wait for a security audit.

4. Use Compiler Flags

Enable compiler-level overflow detection during development and testing:

# GCC/Clang: Enable undefined behavior sanitizer
gcc -fsanitize=undefined,address -o myprogram myprogram.c

# Enable overflow warnings
gcc -Wall -Wextra -Woverflow myprogram.c

5. Consider Safer Abstractions

Where possible, use higher-level abstractions that handle size arithmetic safely:

  • In C++: Use std::vector, std::array, or smart pointers
  • In C: Consider libraries like safe-iop for safe integer operations
  • Use OS/platform APIs that perform bounds checking internally

6. Relevant Security Standards

This vulnerability class is well-documented in the security community:

  • CWE-190: Integer Overflow or Wraparound
  • CWE-122: Heap-based Buffer Overflow
  • CWE-680: Integer Overflow to Buffer Overflow
  • OWASP: Memory Management Cheat Sheet
  • SEI CERT C: Rule INT30-C — Ensure that unsigned integer operations do not wrap
  • SEI CERT C: Rule MEM35-C — Allocate sufficient memory for an object

A Note on Core Dump Parsers and Attack Surface

It's worth pausing to think about where this vulnerability lives: a core dump parser. Core dump analyzers are often run by developers and security researchers on files from production systems, crash reports, or — in adversarial contexts — files submitted by external parties.

This makes the attack surface non-trivial. A malicious actor who can influence the core dump file being analyzed (e.g., by submitting a crash report, or providing a "test" core file) could potentially exploit this vulnerability to compromise the machine running the analyzer. Parsing untrusted binary data is inherently high-risk, and every size field, count field, and offset in such files must be treated as adversarial input.


Conclusion

Integer overflow vulnerabilities in memory allocation are a classic, well-understood bug class — yet they continue to appear in production code. The pattern is deceptively simple: a multiplication that looks correct under normal inputs silently wraps under adversarial ones, producing a buffer that's far too small and setting the stage for heap corruption.

The key takeaways from this fix:

  • 🔍 Always check for overflow before using multiplication to compute allocation sizes
  • 🛡️ Treat all externally-supplied size values as untrusted — validate and bound them
  • 🤖 Use static analysis tools like Semgrep, CodeQL, or Coverity in your CI pipeline to catch these patterns automatically
  • 🧪 Run sanitizers (ASan, UBSan) during testing to catch runtime overflows that static analysis misses
  • 📚 Know your CWEs — CWE-190 and CWE-680 are the canonical references for this vulnerability class

Security is a discipline, not a feature. Catching and fixing bugs like this one — before they reach production — is exactly what a healthy security practice looks like. Kudos to the automated scanner and the team for addressing this promptly.


This vulnerability was identified and fixed as part of an automated security scanning process. The fix was verified by re-scan and code review before merging.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #1018

Related Articles

medium

Integer Overflow in Shared Memory Bounds Check: How a Missing Cast Opened the Door to Arbitrary Memory Writes

A subtle but dangerous integer overflow vulnerability was discovered in `lib/rpmi_shmem.c`, where bounds checks on shared memory operations could be silently bypassed due to 32-bit arithmetic overflow. By carefully crafting `offset` and `len` values, an OS-level or hypervisor-level caller could direct firmware writes to arbitrary memory addresses — including interrupt vector tables and security-critical configuration structures. The fix was elegantly simple: casting operands to 64-bit before add

critical

Heap Overflow in TOML Parser: How Integer Overflow Leads to Memory Corruption

A critical heap buffer overflow vulnerability was discovered and patched in the centitoml TOML parser, where missing integer overflow validation on a `MALLOC(len+1)` call could allow an attacker to trigger memory corruption via a crafted TOML configuration file. The vulnerability (CWE-190) is reachable through community-distributed mod or map files that the game loads from its `config/` directory, making it a realistic attack vector for remote code execution. A targeted one-line guard now preven

critical

Heap Corruption via Unchecked memcpy: How Integer Overflow Bugs Corrupt Memory in Windows File Operations

A critical buffer overflow vulnerability was discovered in `phlib/nativefile.c`, where multiple `memcpy` calls copied filename and extended-attribute data into fixed-size structures without verifying that source lengths didn't exceed destination buffer boundaries. An attacker supplying an oversized filename or EA name could corrupt adjacent heap memory, potentially enabling arbitrary code execution. The fix replaces unchecked arithmetic with Windows' safe integer helpers (`RtlULongAdd`, `RtlULon

critical

Integer Overflow to Heap Buffer Overflow: Fixing a Critical memcpy Bounds Check in libretro-db

A critical heap buffer overflow vulnerability was discovered in `libretro-db/rmsgpack_dom.c`, where a missing integer width cast allowed an attacker-controlled string length value of `UINT32_MAX` to wrap around to zero, completely collapsing the bounds check before a `memcpy` call. The fix is a single targeted cast to `uint64_t` that closes the overflow window and ensures the bounds check behaves correctly regardless of the input value. This class of vulnerability is a textbook example of how in

critical

Critical Integer Sign Bug in runtime_malloc(): How a Missing Check Enables Heap Corruption

A critical vulnerability in `runtime/zenith_runtime.c` allowed the `runtime_malloc()` function to accept negative size values, which when cast to an unsigned type could either trigger a massive failed allocation or produce a dangerously undersized buffer ripe for overflow. The fix adds a simple but essential guard clause that rejects non-positive sizes before they ever reach `malloc()`. Left unpatched, this class of bug can lead to heap metadata corruption, process crashes, or even arbitrary cod

medium

Integer Overflow in Packet Reassembly: How One Missing Check Enables Heap Corruption

A critical heap buffer overflow vulnerability was discovered in the network packet reassembly function of `net_channel_ex.c`, where an attacker-controlled `bodylen` field could be used to corrupt heap memory without any bounds validation. The fix introduces a simple yet effective integer overflow check before accumulating packet body lengths, preventing malformed packets from triggering memory corruption. This type of vulnerability is a stark reminder that even low-level arithmetic operations in