summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2013-01-27 22:38:32 -0800
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-02-02 10:35:22 +0100
commit0da54716647780df0e1b54b03c3e8e007b78bb8a (patch)
treeae71e4a90629afa4f1118da10cfa616558b631ab
parent288d3aceee83192bb84d73c60268a18722488adf (diff)
Work around an unfixed glibc bug in dlclose(3) on exit
During exit, libraries are unloaded and global destructors are run. If we call dlclose(3) from inside the global destructors, we might be telling libdl to unload a module it has already unloaded. I cannot reproduce the issue on my Fedora 17 machine with glibc 2.15, but it could be reliably be reproduced on an Ubuntu 11.10. The assertion is identical to the one reported upstream at http://sourceware.org/bugzilla/show_bug.cgi?id=11941 (see better explanation at https://bugzilla.novell.com/show_bug.cgi?id=622977). I cannot find any evidence in glibc's source code that the bug has been fixed. Change-Id: I97745f89e8c5481196e645dada8762d607a9fb2c Reviewed-by: Lars Knoll <lars.knoll@digia.com>
-rw-r--r--src/corelib/plugin/qlibrary.cpp14
-rw-r--r--src/corelib/plugin/qlibrary_p.h4
2 files changed, 14 insertions, 4 deletions
diff --git a/src/corelib/plugin/qlibrary.cpp b/src/corelib/plugin/qlibrary.cpp
index 7d6c3c3063..40b6b0d150 100644
--- a/src/corelib/plugin/qlibrary.cpp
+++ b/src/corelib/plugin/qlibrary.cpp
@@ -376,7 +376,14 @@ inline void QLibraryStore::cleanup()
Q_ASSERT(lib->pHnd);
Q_ASSERT(lib->libraryUnloadCount.load() > 0);
lib->libraryUnloadCount.store(1);
+#ifdef __GLIBC__
+ // glibc has a bug in unloading from global destructors
+ // see https://bugzilla.novell.com/show_bug.cgi?id=622977
+ // and http://sourceware.org/bugzilla/show_bug.cgi?id=11941
+ lib->unload(QLibraryPrivate::NoUnloadSys);
+#else
lib->unload();
+#endif
delete lib;
it.value() = 0;
}
@@ -490,15 +497,16 @@ bool QLibraryPrivate::load()
return ret;
}
-bool QLibraryPrivate::unload()
+bool QLibraryPrivate::unload(UnloadFlag flag)
{
if (!pHnd)
return false;
if (!libraryUnloadCount.deref()) { // only unload if ALL QLibrary instance wanted to
delete inst.data();
- if (unload_sys()) {
+ if (flag == NoUnloadSys || unload_sys()) {
if (qt_debug_component())
- qWarning() << "QLibraryPrivate::unload succeeded on" << fileName;
+ qWarning() << "QLibraryPrivate::unload succeeded on" << fileName
+ << (flag == NoUnloadSys ? "(faked)" : "");
//when the library is unloaded, we release the reference on it so that 'this'
//can get deleted
libraryRefCount.deref();
diff --git a/src/corelib/plugin/qlibrary_p.h b/src/corelib/plugin/qlibrary_p.h
index 42172167b7..b425e0d590 100644
--- a/src/corelib/plugin/qlibrary_p.h
+++ b/src/corelib/plugin/qlibrary_p.h
@@ -83,12 +83,14 @@ public:
#endif
pHnd;
+ enum UnloadFlag { UnloadSys, NoUnloadSys };
+
QString fileName, qualifiedFileName;
QString fullVersion;
bool load();
bool loadPlugin(); // loads and resolves instance
- bool unload();
+ bool unload(UnloadFlag flag = UnloadSys);
void release();
QFunctionPointer resolve(const char *);