Freeing the same memory allocation more than once.
A double free occurs when `delete`/`free()` is called on the same memory address more than once. The first `delete` returns the memory to the heap allocator. The second `delete` corrupts the allocator's internal data structures, leading to crashes, memory corruption, or — in security contexts — exploitable vulnerabilities.
Common causes: two pointers aliasing the same allocation and both deleting it, a copy constructor or copy assignment that performs a shallow copy (copying the pointer but not deep copying the data), or code paths that reach `delete` multiple times due to logic errors.
1#include <iostream>2 3class Buffer {4public:5 int* data;6 7 Buffer(int size) {8 data = new int[size];9 }10 11 // Compiler-generated copy constructor does a shallow copy!12 ~Buffer() {13 delete[] data; // Both original and copy will call this!14 }15};16 17int main() {18 Buffer buf1(10);19 Buffer buf2 = buf1; // Shallow copy — data pointer is shared!20 21 // When main() exits, both buf1 and buf2 destructors run22 // Both call delete[] on the SAME pointer — double free!23 return 0;24}1#include <iostream>2#include <memory>3#include <algorithm>4 5// Fix 1: Follow the Rule of Five — implement deep copy6class Buffer {7 int* data;8 int size;9public:10 Buffer(int sz) : size(sz), data(new int[sz]) {}11 12 // Deep copy constructor13 Buffer(const Buffer& other) : size(other.size), data(new int[other.size]) {14 std::copy(other.data, other.data + size, data);15 }16 17 // Copy assignment18 Buffer& operator=(const Buffer& other) {19 if (this != &other) {20 delete[] data;21 size = other.size;22 data = new int[size];23 std::copy(other.data, other.data + size, data);24 }25 return *this;26 }27 28 ~Buffer() { delete[] data; }29};30 31// Fix 2 (BEST): Use smart pointers — no manual delete needed32class SafeBuffer {33 std::unique_ptr<int[]> data;34public:35 SafeBuffer(int size) : data(std::make_unique<int[]>(size)) {}36 // unique_ptr's move semantics handle ownership correctly automatically37};38 39int main() {40 Buffer buf1(10);41 Buffer buf2 = buf1; // Deep copy — independent allocations42 // Both destructors free different memory — safe!43 44 return 0;45}Simulate standard system builds to trigger compiler trace records and track memory crashes locally.
The compiler-generated copy constructor copies `data` by value — meaning `buf2.data` and `buf1.data` point to the same memory. When the destructors run (buf2 first, then buf1), they both call `delete[] data` on the same address. The second `delete` causes heap corruption, a likely crash, or undefined behavior.