Safeguard
Application Security•

CWE-1098 Pointer Member Without Copy Control in C++ Classes

CWE-1098 is a class holding a raw pointer with no copy constructor or assignment operator. The default shallow copy leads to double frees and use after free.

Safeguard Security Team
4 min read

CWE-1098, Data Element containing Pointer Item without Proper Copy Control Element, describes code with a data element that holds a pointer but has no associated copy or constructor method.

It is a C++ problem in practice, often called the rule of three or rule of five. MITRE allows the entry for mapping real vulnerabilities, after reading the name and description carefully.

How it happens

When you copy a C++ object, the compiler generates a copy that duplicates each member. For a raw pointer, that means copying the address, not the data it points to. Two objects now point at the same memory, and each believes it owns it.

// Vulnerable pattern: shallow copy of an owning pointer
class Buffer {
    char* data;
public:
    Buffer(size_t n) : data(new char[n]) {}
    ~Buffer() { delete[] data; }
    // no copy constructor, no copy assignment
};

void run() {
    Buffer a(64);
    Buffer b = a;   // b.data and a.data are the same address
}                   // both destructors delete[] it: double free

A double free corrupts the allocator's bookkeeping and has long been a route to memory corruption bugs. A use after free is just as easy to reach: copy, destroy one, keep using the other.

The fix is to say how copying works.

// Fix 1: deep copy
class Buffer {
    char* data;
    size_t size;
public:
    Buffer(size_t n) : data(new char[n]), size(n) {}
    Buffer(const Buffer& o) : data(new char[o.size]), size(o.size) {
        std::copy(o.data, o.data + size, data);
    }
    Buffer& operator=(const Buffer& o) {
        if (this != &o) {
            char* fresh = new char[o.size];
            std::copy(o.data, o.data + o.size, fresh);
            delete[] data;
            data = fresh;
            size = o.size;
        }
        return *this;
    }
    ~Buffer() { delete[] data; }
};
// Fix 2: let the standard library own the memory
class Buffer {
    std::vector<char> data;
public:
    Buffer(size_t n) : data(n) {}
};   // copying, moving and cleanup are all correct by default

The second version is shorter and safer, and it is what most modern C++ guidance recommends.

What an attacker gains

MITRE lists reduced reliability and says that if the code is reachable by an attacker, the reliability problem might introduce a vulnerability. Double free and use after free are memory safety bugs. Whether one is exploitable depends on the surrounding code, but they are never harmless, and a crash alone can be a denial of service.

How to find it

The record gives no detection methods, so use general ones.

  • Search for classes with raw pointer members and no copy operations declared.
  • Compile with warnings that flag classes having a destructor but no copy operations.
  • Run tests under AddressSanitizer, which reports double frees and use after free at the line they happen.
  • Use a static analyzer in CI to flag shallow copies of owning pointers.

How to fix it

  1. Replace owning raw pointers with std::vector, std::string, std::unique_ptr or std::shared_ptr.
  2. If a raw owning pointer stays, define the destructor, copy constructor and copy assignment together, and the move operations if needed.
  3. If copying makes no sense, delete the copy operations explicitly so the compiler rejects them.
  4. Keep ownership clear in comments and names, so a reader can tell who frees what.
// Fix 3: forbid copying
Buffer(const Buffer&) = delete;
Buffer& operator=(const Buffer&) = delete;

Try it yourself

Explore a static scan of a small project to see how code level findings are listed and prioritized.

Click through it at your own pace, or open it full screen.

Quick check

Why does copying a class with a raw pointer cause a double free?

The default copy duplicates the address, so two objects point at the same memory and both destructors free it.

What is the safest way to avoid this?

Do not own memory with raw pointers. Use standard containers or smart pointers, which handle copying and cleanup for you.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.