macOS Framework still loaded in the process memory after dlclose call to the library that links to it

Hello,

I have the 'libTestlib.dylib' which has Linked Dependency to CoreServices.framework

If I call dlopen(libTestlib.dylib), library is loaded successfully. Also CoreServices.framework are loaded even if I do not have any piece of code that uses this framework.

After dlclose(libTestlib), CoreServices.framework is still in the process memory (OS failed to unload it) causing our test library to also still be in the process memory.
If we remove CoreServices.framework from Linked Dependency, the issue is not reproducing anymore.

Also, if we comment std::stringstream from our code, the issue is not reproducing.
It seems there are some issues with std::stringstream and
CoreServices.framework together (maybe CFString?, maybe LLVM? ).

Could you please help on this case and provide a solution on why the CoreServices.framework (and our test library also) is still loaded in the process memory after dlclose?

I have attached both xcode projects, 'libTestlib' and 'SampleApp'. Also, the 'Reproduction' folder contains the already built targets, to reproduce the issue just run

cd "...../Reproduction"
./SampleApp

The output will show the open libraries before and after dlopen call and after dlclose call. You can see that CoreServices.framework is still there after the dlclose(libTestlib).

Many thanks in advance for your help!!

Here are the xcode projects: I cannot attach the sample projects so please advise how to attach them

Under POSIX dlclose() is not guaranteed unload a dylib. This is due to the fact that other dylibs or the system runtime may also have references to the dylib. From its its macOS man page (man 3 dlclose):


dlclose() releases a reference to the dynamic library or bundle referenced by handle.  If the reference count drops to 0, the bundle is removed from the address space, and handle is rendered invalid.  Just before removing a dynamic library or bundle in this way, any termination routines in it are called.  handle is the value returned by a previous call to dlopen.

Prior to Mac OS X 10.5, only bundles could be unloaded.  Starting in Mac OS X 10.5, dynamic libraries may also be unloaded.  There are a couple of cases in which a dynamic library will never be unloaded: 1) the main executable links against it, 2) an API that does not support unloading (e.g. NSAddImage()) was used to load it or some other dynamic library that depends on it, 3) the dynamic library is in dyld's shared cache.

In addition to what is stated in the man page there are several other features that prevent a dylib from being unloaded. Those include declaring any Objective C or Swift classes, as well as declaring any variables to have thread_local storage in C++.
macOS Framework still loaded in the process memory after dlclose call to the library that links to it
 
 
Q