boost::shared_ptr classes across DLL boundaries on Win32 issue

I have been using the boost::shared_ptr class to add large classes to STL containers as shared pointers. I use many DLLs that all share the same heap (they all use multi-threaded DLL runtimes), and shared_ptr's are passed between DLLs. I am currently running into an issue where DLL "A" can build up a shared_ptr in a local variable, and hand ownership over to DLL "B" (which stores the shared pointer in a STL container). I get a crash when the STL container class in DLL B later destructs if DLL A has been unloaded. It seems all virtual functions in the vtable of the shared pointers are bogus at this point. The crash occurs when attempting to call the "dispose()" virtual function as shown below: void release() // nothrow { { #if defined(BOOST_HAS_THREADS) mutex_type::scoped_lock lock(mtx_); #endif long new_use_count = --use_count_; if(new_use_count != 0) return; } dispose(); // <-- Crash is on function call to virtual "dispose" weak_release(); } the stack backtrace below: 0 - boost::detail::sp_counted_base::release() 1 - boost::detail::shared_count::~shared_count() 2 - boost::shared_ptr<T>::~shared_ptr<T>() .... Do I need to fully instantiate and export these template classes from the main DLL (which is DLL "B" in the above example)? Any hints would be most appreciated.

Greg Clayton wrote:
I am currently running into an issue where DLL "A" can build up a shared_ptr in a local variable, and hand ownership over to DLL "B" (which stores the shared pointer in a STL container). I get a crash when the STL container class in DLL B later destructs if DLL A has been unloaded. It seems all virtual functions in the vtable of the shared pointers are bogus at this point. The crash occurs when attempting to call the "dispose()" virtual function as shown below:
Are you sure its nothing as simple as: shared_ptr<T>::~shared_ptr<T> is called from DLL B for a T that was created in DLL A that has been unloaded. This means the code for Ts destructor nolonger exists in memory, so when the shared_ptr actually deletes the T, it tries to call the destructor of T, for which the code nolonger exists so bang, access violation or whatever. You can't unload the DLL while objects from that DLL still exist. Even though DLL B may have its own copy of the code for T, when the vtable for T was set up in DLL A, its pointers all pointed to code in DLL A and therefore, when deleted, will try and execute the destructor code in DLL A which nolonger exists. HTH Russell

On Thu, 5 Feb 2004 23:13:13 -0800, Greg Clayton wrote:
Any hints would be most appreciated.
Well, I'm not sure this is the issue here, but I'd suggest (in DLL and all it's clients) dynamicaly linking to C and C++ runtime (ie. "Multi-threaded DLL (/MD)" or "Multi-threaded Debug DLL (/MDd)"), instead of static runtime. If you already use it, I have not clue what else it could be :( B.

Bronek Kozicki wrote:
On Thu, 5 Feb 2004 23:13:13 -0800, Greg Clayton wrote:
Any hints would be most appreciated.
Well, I'm not sure this is the issue here, but I'd suggest (in DLL and all it's clients) dynamicaly linking to C and C++ runtime (ie. "Multi-threaded DLL (/MD)" or "Multi-threaded Debug DLL (/MDd)"), instead of static runtime. If you already use it, I have not clue what else it could be :(
Actually shared_ptr supports DLLs that use the static runtime; in fact, it is exactly this shared_ptr feature that causes the problem here. :-)

Peter Dimov <pdimov@mmltd.net> wrote:
Well, I'm not sure this is the issue here, but I'd suggest (in DLL and all it's clients) dynamicaly linking to C and C++ runtime (ie. "Multi-threaded DLL (/MD)" or "Multi-threaded Debug DLL (/MDd)"), instead of static runtime. If you already use it, I have not clue what else it could be :(
Actually shared_ptr supports DLLs that use the static runtime; in fact, it is exactly this shared_ptr feature that causes the problem here. :-)
Oh, I see. After reading your previous response in this thread it came to my mind :> B.

Greg Clayton wrote:
I have been using the boost::shared_ptr class to add large classes to STL containers as shared pointers. I use many DLLs that all share the same heap (they all use multi-threaded DLL runtimes), and shared_ptr's are passed between DLLs.
I am currently running into an issue where DLL "A" can build up a shared_ptr in a local variable, and hand ownership over to DLL "B" (which stores the shared pointer in a STL container). I get a crash when the STL container class in DLL B later destructs if DLL A has been unloaded. It seems all virtual functions in the vtable of the shared pointers are bogus at this point.
Yes, that's correct. A shared_ptr<X> remembers who created it (DLL A in this case) and attempts to destroy itself using DLL A. This is by design; DLL B may not be aware of the actual type of the shared_ptr, it may hold shared_ptr<void> or shared_ptr<A> (where A is an abstract base of X). It's even possible for X to not even exist outside DLL A. You need to make sure that DLL A is still in memory when DLL B destroys its shared_ptr.
participants (4)
-
Bronek Kozicki
-
Greg Clayton
-
Peter Dimov
-
Russell Hind