Tutorial :Memory / heap management across DLLs


Although it seems to be a very common issue, I did not harvest much information: How can I create a safe interface between DLL boundaries regarding memory alloction?

It is quite well-known that

// in DLL a  DLLEXPORT MyObject* getObject() { return new MyObject(); }  // in DLL b   MyObject *o = getObject();  delete o;  

might certainly lead to crashes. But since interactions like the one above are - as I dare say - not uncommon, there has to be a way to ensure safe memory allocation.

Of course, one could provide

// in DLL a  DLLEXPORT void deleteObject(MyObject* o) { delete o; }  

but maybe there are better ways (e.g. smart_ptr?). I read about using custom allocators when dealing with STL containers as well.

So my inquiry is more about general pointers to articles and/or literature dealing with this topic. Are there special fallacies to look out for (exception handling?) and is this problem limited to only DLLs or are UNIX shared objects "inflicted" too?


As you suggested, you can use a boost::shared_ptr to handle that problem. In the constructor you can pass a custom cleanup function, which could be the deleteObject-Method of the dll that created the pointer. Example:

boost::shared_ptr< MyObject > Instance( getObject( ), deleteObject );  

If you do not need a C-Interface for your dll, you can have getObject return a shared_ptr.


Overload operator new, operator delete et. al for all your DLL classes and implement them within the DLL:

 void* MyClass::operator new(size_t numb) {      return ::operator new(num_bytes);   }     void MyClass::operator delete(void* p) {      ::operator delete(p);   }   ...  

This can easily be placed in a common base class for all classes exported by the DLL.

This way, allocation and deallocation are done entirely on the DLL heap. Honestly, I'm unsure whether it has any serious pitfalls or portability issues - but it works for me.


You may state that it "might certainly lead to crashes". Funny - "might" means the exact opposite of "certainly".

Now, the statement is mostly historical anyway. There is a very simple solution: Use 1 compiler, 1 compiler setting, and link against the DLL form of the CRT. (And you can probably get away skipping the latter)

There are no specific articles to link to, as this is a non-problem nowadays. You'd need the 1 compiler, 1 setting rule anyway. Simple things as sizeof(std::string) depend on it, and you'd have massive ODR violations otherwise.


Some pointers:


Another option which may be applicable in some circumstances is to keep all allocation and deallocate inside the DLL and prevent the object crossing that boundary. You can do this by providing a handle so that creating a MyObject creates it inside the DLL code and returns a simple handle (eg an unsigned int) through which all operations by the client are performed:

// Client code  ObjHandle h=dllPtr->CreateObject();  dllPtr->DoOperation(h);  dllPtr->DestroyObject(h);  

Since all the allocation happens inside the dll you can ensure that it gets cleaned up by wrapping in a shared_ptr. This is pretty much the method suggested by John Lakos in Large Scale C++.


In a "layered" architecture (very common scenario) the deepest lying component is responsible for providing a policy on the question (could be returning shared_ptr<> as suggested above or "the caller is responsible for deleting this" or "never delete this, but call releaseFooObject() when done and don't access it afterwards" or ...) and the component nearer the user is responsible for following that policy.

Bi-directional information flow makes the responsibilities harder to characterize.

is this problem limited to only DLLs or are UNIX shared objects "inflicted" too?

Actually it's worse than that: you can have this problem just as easily with statically linked libraries. It is the existence of code boundaries inside a single execution context that makes for a chance to misuse or mis-communicate about some facility.


It is quite well-known that

// in DLL a  DLLEXPORT MyObject* getObject() { return new MyObject(); }  // in DLL b   MyObject *o = getObject();  delete o;  

might certainly lead to crashes.

Whether or not the above has a well-defined characteristic depends on how the MyObjecttype is defined.

Iff the class has a virtual destructor, (and that destructor is not defined inline), than it will not crash and will exhibit well-defined behavior.

The reason normally cited for why this crashes is that delete does two things:

  • call destructor
  • free memory (by calling operator delete(void* ...))

For a class with a non-virtual destructor, it can do these things "inline", which leads to the situation that delete inside DLL "b" may try to free memory from the "a" heap == crash.

However, if the destructor of MyObject is virtual then before calling the "free" function, the compiler needs to determine the actual run-time class of the pointer before it can pass the correct pointer to operator delete():

C++ mandates that you must pass the exact same address to operator delete as what operator new returns. When you’re allocating an object using new, the compiler implicitly knows the concrete type of the object (which is what the compiler uses to pass in the correct memory size to operator new, for example.)

However, if your class has a base class with a virtual destructor, and your object is deleted through a pointer to the base class, the compiler doesn’t know the concrete type at the call site, and therefore cannot compute the correct address to pass to operator delete(). Why, you may ask? Because in presence of multiple inheritance, the base class pointer’s address may be different to the object’s address in memory.

So, what happens in that case is that when you delete an object which has a virtual destructor, the compiler calls what is called a deleting destructor instead of the usual sequence of a call to the normal destructor followed by operator delete() to reclaim the memory.

Since the deleting destructor is a virtual function, at runtime the implementation of the concrete type will be called, and that implementation is capable of computing the correct address for the object in memory. What that implementation does is call the regular destructor, compute the correct address of the object, and then call operator delete() on that address.

It seems that both GCC (from the linked article) and MSVC achieve this by calling both the dtor as well as the "free" function from the context of a "deleting destructor". And this helper by necessity lives inside your DLL and will always use the correct heap, even if "a" and "b" have a different one.


I have written an article about using C++11's custom deleter facilities of unique_ptr to pass objects through DLL boundaries (or shared object libraries in Linux). The method described in the article do not "pollute" the unique_ptr signature with the deleter.

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Next Post »