[Boost::any] Memory management using dynamic libraries
I'm building a framework which needs to allow communication between shared libraries which are loaded at runtime. Each shared library provides its own implementation of an abstract interface contained in the framework (called Module), and all Modules are called sequentially multiple times doing the work they need to do. Since modules need to communicate with each other with custom data types, I though of using an std::unordered_mapstd::string,boost::any kept by the framework and shared with the Modules. The map is filled and read by the modules when their code is called through the Module interface which the framework knows (virtual functions). However after a bug I realized that each boost::any value is allocated by the modules, which is logical, since the framework itself has no knowledge of the types that will be stored in the map, and thus the code to allocate them must reside in the libraries themselves. I was wondering whether this could be a problem both during overwriting of a map value (since boost::any has to destroy its old contents) and during program shutdown. This could maybe be because modules use their own allocators. The problem that I had, for example, resulted in a segfault if I tried to unload the modules from memory before the destruction of the map (which is owned by the framework), during boost::any destruction. I assume this happened because the contents of boost::any were created in memory that was then unloaded during the unloading of the shared libraries, resulting in the segfault. And this yet does not take into account custom allocators! So I'm wondering what the best approach here would be. If I would need to keep track of the current "owner" of each single boost::any value allocated, and use it to manually destroy instances when required, or if there is a better way, maybe using some particular boost::any property. Many thanks in advance!
On 25 December 2013 09:26, Eugenio Bargiacchi
I'm building a framework which needs to allow communication between shared libraries which are loaded at runtime.
The problem that I had, for example, resulted in a segfault if I tried to unload the modules from memory before the destruction of the map (which is owned by the framework), during boost::any destruction.
Unloading shared libraries in C++ is fraught with peril. Could the problem be that you've unloaded the code for the destructor of the object stored in the boost::any object? -- Nevin ":-)" Liber mailto:nevin@eviloverlord.com (847) 691-1404
I've tried to instantiate a simple integer, but the problem persists
(not sure if it even matters though). Though if a value is created
from the framework, I have no problems deleting it no matter the
modules' status, so something of that sort must be going on.
As for unloading shared libraries, I don't really think I will need it
at runtime, though the program will need to close at one point, and I
just want the whole thing to be as clean as possible without just
sweeping the problem away because it only happens during shutdown.
However, if my problem can be solved by simply destroying the map
before unloading all shared libraries, I am content. What I am most
concerned about is whether every single time a module destroys a value
it needs to somehow give control back to the module that created it so
that it can destroy it, or if that is handled automatically when a
destructor is called.
On 12/26/13, Nevin Liber
On 25 December 2013 09:26, Eugenio Bargiacchi
wrote: I'm building a framework which needs to allow communication between shared libraries which are loaded at runtime.
The problem that I had, for example, resulted in a segfault if I tried to unload the modules from memory before the destruction of the map (which is owned by the framework), during boost::any destruction.
Unloading shared libraries in C++ is fraught with peril.
Could the problem be that you've unloaded the code for the destructor of the object stored in the boost::any object? -- Nevin ":-)" Liber mailto:nevin@eviloverlord.com (847) 691-1404
On 27/12/2013 07:27, Quoth Eugenio Bargiacchi:
However, if my problem can be solved by simply destroying the map before unloading all shared libraries, I am content. What I am most concerned about is whether every single time a module destroys a value it needs to somehow give control back to the module that created it so that it can destroy it, or if that is handled automatically when a destructor is called.
If the type explicitly defines a non-inline destructor, then it will actually call the destructor in the module. If you use an inline destructor or compiler-generated destructor then it might or might not depending on how the compiler was feeling at the time. The peril doesn't end there though. Even if you guarantee that it will call the destructor in the module, two different modules might not have the same memory allocator (especially if there's a chance they might be compiled with different compilers or even different versions), and weird things may happen if you allocate memory in one module and try to deallocate it in another. Some smart pointer objects (eg. shared_ptr) let you provide an explicit "deleter" function that gets called when the pointee needs to be destroyed, which can help mitigate some cases of objects passing between modules. But there still be dragons.
participants (3)
-
Eugenio Bargiacchi
-
Gavin Lambert
-
Nevin Liber