On 17/09/2021 11:13, Alex Peshkoff via Firebird-devel wrote: > On 9/17/21 12:44 PM, Dimitry Sibiryakov wrote: >> Alex Peshkoff via Firebird-devel wrote 17.09.2021 9:08: >>> Is it about a library dynamically (dlopen, LoadLibrary) loaded or >>> linked to the exacutable? >> >> Both. The library tree is the same (at least on Linux). >> > > Tree is the same - but cleanup order (at least on linux) differs. > First of all dynamically loaded libraries are unloaded in reverse order, > next invoken executable dtors/atexits, and only after it - dtors of > linked libraries. > Check yourself if in doubt. >
I'm not looking at order between different libraries at the moment. I'm creating a possible solution for more safe integration of our memory manager cleanup with more common code, possible implemented in external libraries that we do not have full control. With the atexit trick, and initialize the memory manager and mutex on demand, things improves. But it still crashed code with boost.test integrated. Boost.test has a global function (GF) with a static object (GFO) inside it. So when this function is called for the first time it initializes that object. Everything ok here. But in other cpp files there is the tests. Tests instantiates new objects (via static storage) and register that tests on GFO (returned calling GF). Each object instantiated with new operator is initialized after the memory manager initialization. Hence, memory manager cleanup happens after it and everything is ok. But relation of GFO and the memory manager does not exist. GFO may be initialized before the memory manager and is cleaned up after it. But GFO destructor destroy the tests objects. We may think in a much more simple case as a global std::unique_ptr<std::string> where the string is set later after global initialization. That smart pointer may be cleaned up after the memory manager. For the boost.test case a solution exist (maybe not completely reliable). Since it have a .cpp-like file which is included in a .cpp file of us, I have created a DefaultMemoryPoolGuard RAII class put in our .cpp file, before inclusion of boost.test. It makes memory manager cleanup run later. But this is very boost.test specific and will not work in other cases. But we have two kind of external projects. Shared libraries (say ICU) and static libraries (say RE2). If ICU does not cleanup its memory properly, we'll have memory leaks after it's unloaded, as it does not use our memory manager. RE2 global objects (if existent) are destroyed with our default memory pool, but if it does the things I'm saying here, we'll have crashes or undefined behavior. I think we can improve things here. We have our GlobalPtr, InitInstance and we may continue using them. And we have FB_NEW which allocates memory from the global default pool. We may split that global default pool in two, so we'll have another default pool for external (not controlled by us) libraries. All memory allocated directly with "operator new" (not FB_NEW) will go to external pool. And external pool will not be cleaned up on exit. Like we already have with ICU memory. Of course we didn't intend to have all external code cleaning things and we leak that pool structures, so it may have some special things. Once we are destructing it if there is no memory allocated from it anymore, it must be completely freed. Since it's a different pool, we may debug it and understand better how the libraries we're using are doing with it. Adriano Firebird-Devel mailing list, web interface at https://lists.sourceforge.net/lists/listinfo/firebird-devel