When Your Heap Corrupts
Table of Contents
- What is Heap Corruption?
- Common Causes
- Symptoms & Detection
- Debugging Tools
- Fixing the Corruption
- Prevention Strategies
- Real-World Case Studies
- Further Reading
1. What is Heap Corruption? <a name=”what-is-heap-corruption”></a>
Heap corruption occurs when:
- Memory is written outside allocated bounds (buffer overflow)
- Freed memory is reused (use-after-free)
- Memory is double-freed
- Heap metadata is overwritten
Why it’s a nightmare:
💀 Silent corruption (fails later, far from the bug)
💀 Non-deterministic crashes (works 99% of the time)
💀 Security vulnerabilities (RCE, privilege escalation)
2. Common Causes <a name=”common-causes”></a>
| Bug Type | Example (C) | Rust Equivalent (Unsafe) |
|---|---|---|
| Buffer overflow | char buf[8]; strcpy(buf, "too long"); | unsafe { *ptr.add(100) = 42; } |
| Use-after-free | free(ptr); printf("%d", *ptr); | unsafe { Box::from_raw(ptr); } |
| Double-free | free(ptr); free(ptr); | unsafe { alloc::dealloc(ptr); } twice |
| Invalid free | free(&stack_var); | unsafe { dealloc(&u32 as *const _ as *mut u8); } |
3. Symptoms & Detection <a name=”symptoms”></a>
Telltale Signs
🔴 malloc(): corrupted top size (glibc)
🔴 Segmentation fault in free() or realloc()
🔴 Data mysteriously changes (unrelated variables modified)
Debugging Flags
- Linux:
export MALLOC_CHECK_=1(glibc rudimentary checks) - Windows: Enable Page Heap (
gflags.exe /i your_app.exe +hpa)
4. Debugging Tools <a name=”tools”></a>
Memory Debuggers
| Tool | Language | Key Feature |
|---|---|---|
| AddressSanitizer (ASan) | C/C++/Rust | Detects out-of-bounds, use-after-free |
| Valgrind | C/C++ | Slow but thorough |
| Dr. Memory | C/C++ | Windows alternative to Valgrind |
| Electric Fence | C/C++ | Immediate crash on overflow |
ASan Example
bash
# Compile with ASan clang -fsanitize=address -g buggy_code.c # Run ./a.out # Crash with detailed ASan report
Sample ASan Output:
text
==ERROR: AddressSanitizer: heap-buffer-overflow
WRITE of size 4 at 0x60200000effc thread T0
#0 in buggy_function() at buggy_code.c:42
5. Fixing the Corruption <a name=”fixes”></a>
Step-by-Step Diagnosis
- Reproduce (enable core dumps:
ulimit -c unlimited) - Backtrace (
gdb ./a.out core) - Isolate (bisect with
git bisect) - Instrument (add logging before suspected code)
Common Fixes
- Replace unsafe functions:
strcpy()→strncpy() - Use guard pages: Allocate extra memory as buffer zones
- Enable asserts:
assert(p != NULL && "Pointer is null!");
Rust-Specific Protections
rust
// Safe Rust prevents these by default:
// let mut v = vec![1, 2, 3];
// v[100] = 42; // Bounds-checked panic
// But unsafe blocks can still corrupt:
unsafe { *ptr.add(100) = 42; } // 😱
6. Prevention Strategies <a name=”prevention”></a>
Code Safeguards
✅ Bounds checking (even in C: if (i < buf_len) buf[i] = x;)
✅ Static analyzers:
clang-tidy(C/C++)rust-clippy(Rust)
✅ Fuzz testing (libFuzzer,AFL)
Memory Allocators
- jemalloc (reduces fragmentation)
- mimalloc (Microsoft’s secure allocator)
Rust-Specific Tips
- Prefer
Vec/Boxover raw pointers - Use
#[cfg(debug_assertions)]for extra checks in dev
7. Real-World Case Studies <a name=”case-studies”></a>
Case 1: The 1-Byte Overflow (CVE-2021-3156)
- Bug:
sudoheap overflow in command parsing - Impact: Root privilege escalation
- Fix: Proper bounds checks in
sudoersparser
Case 2: Rust Vec::from_raw_parts Safety
- Bug: Unsafe usage led to UB in a crypto library
- Lesson: Even Rust needs audit for
unsafeblocks
8. Further Reading <a name=”further-reading”></a>
📚 Books:
- “The Art of Debugging” by Matloff & Salzman
- “Rust for Rustaceans” (Jon Gjengset)
🔗 Tools:
Final Advice
🔧 When you suspect heap corruption:
- Don’t panic (but do enable ASan)
- Simplify (comment out code until bug disappears)
- Document (add comments to warn future devs)
Challenge: Try fuzzing your code with cargo fuzz (Rust) or AFL (C/C++)!
Filed under: Kernel Dives - @ July 21, 2025 12:21 pm