double free without any dynamic memory allocation

advertisements

In general, what could cause a double free in a program that is does not contain any dynamic memory allocation?

To be more precise, none of my code uses dynamic allocation. I'm using STL, but it's much more likely to be something I did wrong than for it to be a broken implmentation of G++/glibc/STL.

I've searched around trying to find an answer to this, but I wasn't able to find any example of this error being generated without any dynamic memory allocations.

I'd love to share the code that was generating this error, but I'm not permitted to release it and I don't know how to reduce the problem to something small enough to be given here. I'll do my best to describe the gist of what my code was doing.

The error was being thrown when leaving a function, and the stack trace showed that it was coming from the destructor of a std::vector<std::set<std::string>>. Some number of elements in the vector were being initialized by emplace_back(). In a last ditch attempt, I changed it to push_back({{}}) and the problem went away. The problem could also be avoided by setting the environment variable MALLOC_CHECK_=2. By my understanding, that environment variable should have caused glibc to abort with more information rather than cause the error to go away.

This question is only being asked to serve my curiosity, so I'll settle for a shot in the dark answer. The best I have been able to come up with is that it was a compiler bug, but it's always my fault.


In general, what could cause a double free in a program that is does not contain any dynamic memory allocation?

Normally when you make a copy of a type which dynamically allocates memory but doesn't follow rule of three

struct Type
{
   Type() : ptr = new int(3) { }
   ~Type() { delete ptr; }
   // no copy constructor is defined
   // no copy assign operator is defined

private:
   int * ptr;
};

void func()
{
   {
     std::vector<Type> objs;
     Type t; // allocates ptr
     objs.push_back(t); // make a copy of t, now t->ptr and objs[0]->ptr point to same memory location
     // when this scope finishes, t will be destroyed, its destructor will be called and it will try to delete ptr;
     // objs go out of scope, elements in objs will be destroyed, their destructors are called, and delete ptr; will be executed again. That's double free on same pointer.
   }
}