C++ Heap Corruption: Double Free, Wrong delete[], and Detection

C++ Heap Corruption: Double Free, Wrong delete[], and Detection

이 글의 핵심

Practical guide to heap corruption: causes, tools, and prevention.

What is heap corruption?

Damage to heap bookkeeping or adjacent memory, often from out-of-bounds writes or invalid free/delete.

int* arr = new int[10];
arr[10] = 42;  // out of bounds
delete[] arr;

Common causes

int* arr = new int[10];
arr[15] = 42;

int* ptr = new int(10);
delete ptr;
delete ptr;

int* arr = new int[10];
delete arr;  // should be delete[]

int* ptr = new int(10);
delete ptr;
*ptr = 42;

Examples

Example 1: Buffer overflow on the heap

#include <iostream>
#include <cstring>

void bufferOverflow() {
    char* buffer = new char[10];
    strcpy(buffer, "This is too long");
    delete[] buffer;
}

void safeBuffer() {
    char* buffer = new char[20];
    strncpy(buffer, "This is safe", 19);
    buffer[19] = '\0';
    delete[] buffer;
}

void useString() {
    std::string str = "This is safe";
}

Example 2: Double free

#include <memory>

void doubleFree() {
    int* ptr = new int(10);
    delete ptr;
    delete ptr;
}

void safeFree() {
    int* ptr = new int(10);
    delete ptr;
    ptr = nullptr;
    delete ptr;
}

void smartPointer() {
    auto ptr = std::make_unique<int>(10);
}

Example 3: Wrong delete

void wrongDelete() {
    int* arr = new int[10];
    delete arr;
}

void correctDelete() {
    int* arr = new int[10];
    delete[] arr;
    
    int* ptr = new int(10);
    delete ptr;
}

void smartPointer() {
    auto arr = std::make_unique<int[]>(10);
    auto ptr = std::make_unique<int>(10);
}

Example 4: Use-after-free

#include <iostream>

void useAfterFree() {
    int* ptr = new int(10);
    delete ptr;
    std::cout << *ptr << std::endl;
}

void safeUse() {
    int* ptr = new int(10);
    std::cout << *ptr << std::endl;
    delete ptr;
}

void smartPointer() {
    auto ptr = std::make_unique<int>(10);
    std::cout << *ptr << std::endl;
}

Detection

// ASan: g++ -fsanitize=address -g program.cpp
// Valgrind: valgrind --tool=memcheck ./program

Common pitfalls

Pitfall 1: Off-by-one loops

int* arr = new int[10];
for (int i = 0; i < 10; i++) {
    arr[i] = i;
}
delete[] arr;

std::vector<int> vec(10);

Pitfall 2: Mixing new and realloc

std::vector<int> vec(10);
vec.resize(20);

Pitfall 3: Pointer arithmetic out of range

int* arr = new int[10];
if (index < 10) {
    arr[index] = 42;
}
delete[] arr;

Pitfall 4: Struct members not freed

struct Node {
    int* data;
    Node* next;
};

void deleteNode(Node* node) {
    delete[] node->data;
    delete node;
}

struct NodeSafe {
    std::unique_ptr<int[]> data;
    std::unique_ptr<NodeSafe> next;
};

Prevention

auto ptr = std::make_unique<int>(10);
auto arr = std::make_unique<int[]>(10);
std::vector<int> vec(10);

Debugging tools

g++ -fsanitize=address -g program.cpp
./a.out

valgrind --leak-check=full --show-leak-kinds=all ./program

FAQ

Q1: When does heap corruption happen?

A: Overflows, double free, wrong delete form, UAF.

Q2: Detection?

A: ASan, Valgrind, debug heap (platform-specific).

Q3: Prevention?

A: Smart pointers, containers, RAII.

Q4: Symptoms?

A: Crashes, flaky behavior, corruption far from the bug.

Q5: delete vs delete[]?

A: delete for single object; delete[] for new[] arrays.

Q6: Resources?

A: Effective C++, ASan docs, Valgrind docs.


See also

  • C++ use-after-free
  • C++ memory leak
  • C++ sanitizers

Practical tips

Debugging

  • Warnings first
  • Small repro

Performance

  • Profile first

Code review

  • Conventions

Checklist

Before coding

  • Right approach?
  • Maintainable?
  • Performance?

While coding

  • Warnings?
  • Edge cases?
  • Errors?

At review

  • Clear?
  • Tests?
  • Docs?

Keywords

C++, heap corruption, heap, memory, debugging, ASan.


  • C++ memory leak
  • C++ sanitizers
  • C++ use-after-free
  • C++ Valgrind
  • C++ algorithm heap