From 220f791f9ab69bcf1d23537b6ed4f68e230ef81b Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 23 May 2012 16:03:40 +0200 Subject: Make QLocale "unload" the ICU libraries upon exit Right now, valgrind reports that there is some reachable memory in QLibrary because we don't call unload() in the libraries we loaded. So do unload() them. Unfortunately, ICU seems to have some global statics it doesn't free. If we really unload the libraries, valgrind will report a leak. So use the PreventUnloadHint, which causes libdl to not actually unload the libraries. Change-Id: I273f09627e27b9116366ddc427e1f3f53ea0f61a Reviewed-by: Denis Dzyubenko Reviewed-by: Thiago Macieira Reviewed-by: Lars Knoll --- src/corelib/tools/qlocale_icu.cpp | 72 ++++++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 19 deletions(-) (limited to 'src/corelib/tools/qlocale_icu.cpp') diff --git a/src/corelib/tools/qlocale_icu.cpp b/src/corelib/tools/qlocale_icu.cpp index eac80b2a92..42651aa745 100644 --- a/src/corelib/tools/qlocale_icu.cpp +++ b/src/corelib/tools/qlocale_icu.cpp @@ -70,27 +70,66 @@ static LibLoadStatus status = NotLoaded; static UCollator *icuCollator = 0; +namespace { +struct Libraries { + QLibrary libicui18n; + QLibrary libicuuc; + ~Libraries() + { + if (icuCollator) { + ptr_ucol_close(icuCollator); + icuCollator = 0; + } + + libicui18n.unload(); + libicuuc.unload(); + } +}; +} +Q_GLOBAL_STATIC(Libraries, icuLibraries) +static bool loadIcuLibrary(QLibrary &lib, const QString &name) +{ +#ifdef Q_OS_WIN + // QLibrary on Windows does not use the version number, the libraries + // are named "icuin.dll", though. + lib.setFileName(name); +#else + // on Unix, we can use the version number + lib.setFileNameAndVersion(name, QStringLiteral(U_ICU_VERSION_SHORT)); +#endif + + // the ICU libraries appear to allocate global statics and not free them + // set the PreventUnloadHint so that we can unload the QLibrary object and + // delete it, but the libraries themselves remain in memory + lib.setLoadHints(QLibrary::PreventUnloadHint); + return lib.load(); +} + +// this function is NOT THREAD-SAFE! bool qt_initIcu(const QString &localeString) { - if (status == ErrorLoading) + if (status == ErrorLoading || !icuLibraries()) return false; if (status == NotLoaded) { // resolve libicui18n - const QString version = QString::fromLatin1(U_ICU_VERSION_SHORT); #ifdef Q_OS_WIN // QLibrary on Windows does not use the version number, the libraries // are named "icuin.dll", though. - QString libName = QStringLiteral("icuin") + version; + // QStringLiteral should work here and will work when MSVC fully supports C++11 + // unfortunately, current versions have do not support proper string concatenation + QString libicui18nName = QLatin1String("icuin" U_ICU_VERSION_SHORT); + QString libicuucName = QLatin1String("icuuc" U_ICU_VERSION_SHORT); #else - QString libName = QStringLiteral("icui18n"); + QString libicui18nName = QStringLiteral("icui18n"); + QString libicuucName = QStringLiteral("icuuc"); #endif - QLibrary lib(libName, version); - if (!lib.load()) { - qWarning("Unable to load library '%s' version %s: %s", - qPrintable(libName), qPrintable(version), + QLibrary &lib = icuLibraries()->libicui18n; + if (!loadIcuLibrary(lib, libicui18nName)) { + qWarning("Unable to load library '%s' version " U_ICU_VERSION_SHORT ": %s", + qPrintable(libicui18nName), qPrintable(lib.errorString())); status = ErrorLoading; return false; @@ -112,21 +151,16 @@ bool qt_initIcu(const QString &localeString) ptr_ucol_close = 0; ptr_ucol_strcoll = 0; - qWarning("Unable to find symbols in '%s'.", qPrintable(libName)); + qWarning("Unable to find symbols in '%s'.", qPrintable(libicui18nName)); status = ErrorLoading; return false; } // resolve libicuuc -#ifdef Q_OS_WIN - libName = QStringLiteral("icuuc") + version; -#else - libName = QStringLiteral("icuuc"); -#endif - QLibrary ucLib(libName, version); - if (!ucLib.load()) { - qWarning("Unable to load library '%s' version %s: %s", - qPrintable(libName), qPrintable(version), + QLibrary &ucLib = icuLibraries()->libicuuc; + if (!loadIcuLibrary(ucLib, libicuucName)) { + qWarning("Unable to load library '%s' version " U_ICU_VERSION_SHORT ": %s", + qPrintable(libicuucName), qPrintable(ucLib.errorString())); status = ErrorLoading; return false; @@ -144,7 +178,7 @@ bool qt_initIcu(const QString &localeString) ptr_u_strToUpper = 0; ptr_u_strToLower = 0; - qWarning("Unable to find symbols in '%s'", qPrintable(libName)); + qWarning("Unable to find symbols in '%s'", qPrintable(libicuucName)); status = ErrorLoading; return false; } -- cgit v1.2.3