Memory leak when repeatedly unloading libdbus with dlclose
Hi, we're running into an issue where we have a shared library that loads dbus with dlopen, and this is causing valgrind to report memory leaks when an app uses that shared library. Based on https://gitlab.freedesktop.org/dbus/dbus/-/blob/master/README.valgrind, the primary remedy for detected leaks from dbus is to call dbus_shutdown to force dbus to free the memory that it has allocated, and I've confirmed that adding a call to dbus_shutdown to our shared library before dlclose-ing libdbus does fix the memory leak. However, from the dbus_shutdown documentation:
You have to know that nobody is using libdbus in your application's process before you can call dbus_shutdown(). One implication of this is that calling dbus_shutdown() from a library is almost certainly wrong, since you don't know what the rest of the app is up to. So, because we are in a shared library, it seems like there is currently no way to properly avoid the memory leak.
I've attached a sample app that links with a sample shared library that dlopens libdbus, creates a connection, closes the connection, and dlcloses libdbus. The sample app calls the shared library's initialization and shutdown functions in a loop, and each time it does so, more memory is leaked, since dbus is reinitialized but never gets torn down. Building the app with make
and running with LD_LIBRARY_PATH=. valgrind --leak-check=full --show-leak-kinds=all ./app 1
outputs:
==22315== LEAK SUMMARY:
==22315== definitely lost: 988 bytes in 21 blocks
==22315== indirectly lost: 9,217 bytes in 60 blocks
==22315== possibly lost: 0 bytes in 0 blocks
==22315== still reachable: 3,513 bytes in 10 blocks
==22315== suppressed: 0 bytes in 0 blocks
while running LD_LIBRARY_PATH=. valgrind --leak-check=full --show-leak-kinds=all ./app 10
(to load/unload dbus 10 times instead of once) outputs:
==22333== LEAK SUMMARY:
==22333== definitely lost: 9,880 bytes in 210 blocks
==22333== indirectly lost: 92,171 bytes in 600 blocks
==22333== possibly lost: 0 bytes in 0 blocks
==22333== still reachable: 3,449 bytes in 8 blocks
==22333== suppressed: 0 bytes in 0 blocks
So it's not just a constant amount of memory that gets leaked. Every time dbus is loaded again, it reallocates it's memory and the memory leak gets worse.
I tried building a local copy of dbus and adding __attribute__ ((destructor))
to dbus_shutdown so that when libdbus gets unloaded dbus_shutdown will get called to free the allocated memory, and that also fixes the memory leak. Because the destructor doesn't get called until libdbus is unloaded, it gets around the issue of calling dbus_shutdown from within a shared library while still ensuring that it does get called when necessary, but I'm not sure if there is another reason that's not done currently.