Incorrect memory deallocation

An improper value was passed to a memory deallocation routine.

This error indicates that the value being passed to a memory deallocation routine did not come from a call to the matching memory allocation routine. There are two common forms of this error. The first is an attempt to free something that was not allocated, such as the address of a static variable or a string literal. The second is an attempt to pass a value obtained from the allocation routine of one memory allocator to the deallocation routine of another memory allocator. For example, a value obtained from "malloc" must be deallocated with "free", not "delete."

C++ has two forms of delete: "delete" and "delete []", the array deallocator. The difference is only significant when freeing an array of class objects that have a non-trivial destructor. In this case, the array delete deallocator calls the destructor for each object in the array, while the ordinary delete deallocator does not. Calling the ordinary deallocator instead of the array deallocator in such cases effectively violates C++ object semantics and can result in memory leaks or other errors.

As a general rule of thumb, an object obtained from an array allocator should always be deallocated with the array deallocator, even if it is safe to use the ordinary deallocator. This protects against future errors if the class is modified in such a way that the destructor becomes non-trivial. However, this diagnostic is not emitted in cases where the ordinary deallocator is used to release arrays of simple objects.

It is good practice to avoid using a single pointer variable to hold values obtained from different allocators at different times, as this creates confusion about how that storage should be properly deallocated.

ID

Observation

Description

1

Deallocation site

The place the inappropriate value is freed

Examples


#include <stdlib>
#include <new>

// A class with non-trivial destructor
class NonTrivial {
private:
    char *m_string;
public:
    // Constructor allocates m_string
    NonTrivial() { m_string = new char[10]; }
    
    // Destructor frees m_string
    ~NonTrivial() { delete m_string; }
    
    // Copy constructor doesn't copy m_string field
    NonTrivial(const NonTrivial & source)
      : m_string(new char[10])
    {
        for (int i = 0; i < 10; i++) {
            m_string[i] = source.m_string[i];
        }
    }

    // Assignment operator doesn't assign m_string field
    NonTrivial& NonTrivial::operator=(const NonTrivial & source)
    {
        for (int i = 0; i < 10; i++) {
            m_string[i] = source.m_string[i];
        }
        return *this;
    }
};

char c;
NonTrivial glob;

int main(int argc, char **argv)
{
    NonTrivial *p1 = new NonTrivial[10];
    NonTrivial *p2 = new NonTrivial(glob); // copy constructor
    char *p3 = "abcd";
    char *p4 = &c;
    *p1 = *p2;
    *p4 = *p3; // assignment operator
    delete p1; // bad: should use delete []
    free(p2);  // bad: should use delete
    free(p3);  // bad: not allocated object
    free(p4);  // bad: not allocated object
    delete &c; // bad: not allocated object
}
        

Copyright © 2010, Intel Corporation. All rights reserved.