summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKai Köhne <[email protected]>2025-05-27 15:21:19 +0200
committerQt Cherry-pick Bot <[email protected]>2025-06-30 13:39:14 +0000
commitec3a4590fd35ff9e674ecd77173f1ab0323b19f7 (patch)
tree88d79d8276d60272d46071dceb8e9048a76bacdf
parent9a71859debc5fb02479f05e9b7a9772ebc5496a4 (diff)
QTranslator: Protect QTranslator data from being accessed while altered
The existing mutex in QCoreApplicationPrivate already protects access to translation data while QCA::installTranslator(), ::removeTranslator() are running. Extend this to also protect the altering methods in the QTranslator class itself. This makes sure that the installed QTranslator objects can be safely altered via QTranslator::load(). As loading translations might actually take a while, we don't want to unnecessarily lock the mutex for QTranslator objects that are _not_ registered. Instead, the patch introduces a QCAPrivate::mutexLockerForTranslator() method that returns a std::unique_lock<> object. If the QTranslator is not registered, the mutex is instantly unlocked in the method. If it is registered, the mutex is only unlocked after the scope of the calling code is exited (so the end of QTranslator::load()). Unfortunately, QWriteLocker does not support std::move semantics. Therefore switch to a simple std::unique_lock/QMutex. This means that QCoreApplication::translate() cannot be executed concurrently from multiple threads anymore, but that is arguably not the most common case, anyhow. While at it, remove the QTranslatorList typedef. Task-number: QTBUG-137179 Change-Id: Id5c7abf0e7664058cb07cf76a0e9532533e37ad3 Reviewed-by: Thiago Macieira <[email protected]> (cherry picked from commit 46b2a0c1b6de152fee37bfe0b39e3f2b11ba1b15) Reviewed-by: Qt Cherry-pick Bot <[email protected]>
-rw-r--r--src/corelib/kernel/qcoreapplication.cpp24
-rw-r--r--src/corelib/kernel/qcoreapplication_p.h12
-rw-r--r--src/corelib/kernel/qtranslator.cpp23
3 files changed, 42 insertions, 17 deletions
diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp
index 3b92c5f48f2..a19e39685f1 100644
--- a/src/corelib/kernel/qcoreapplication.cpp
+++ b/src/corelib/kernel/qcoreapplication.cpp
@@ -2189,7 +2189,7 @@ bool QCoreApplication::installTranslator(QTranslator *translationFile)
QCoreApplicationPrivate *d = self->d_func();
{
- QWriteLocker locker(&d->translateMutex);
+ QMutexLocker locker(&d->translateMutex);
d->translators.prepend(translationFile);
}
@@ -2221,7 +2221,7 @@ bool QCoreApplication::removeTranslator(QTranslator *translationFile)
if (!QCoreApplicationPrivate::checkInstance("removeTranslator"))
return false;
QCoreApplicationPrivate *d = self->d_func();
- QWriteLocker locker(&d->translateMutex);
+ QMutexLocker locker(&d->translateMutex);
if (d->translators.removeAll(translationFile)) {
#ifndef QT_NO_QOBJECT
locker.unlock();
@@ -2306,7 +2306,7 @@ QString QCoreApplication::translate(const char *context, const char *sourceText,
if (self) {
QCoreApplicationPrivate *d = self->d_func();
- QReadLocker locker(&d->translateMutex);
+ QMutexLocker locker(&d->translateMutex);
if (!d->translators.isEmpty()) {
QList<QTranslator*>::ConstIterator it;
QTranslator *translationFile;
@@ -2332,13 +2332,23 @@ QString qtTrId(const char *id, int n)
return QCoreApplication::translate(nullptr, id, nullptr, n);
}
-bool QCoreApplicationPrivate::isTranslatorInstalled(QTranslator *translator)
+/*!
+ \internal
+ Returns a locked mutex handle if \a translator is registered in QCoreApplication,
+ and might be therefore queried for translations from other threads.
+ Returns an unlocked/dummy QMutexLocker otherwise.
+ */
+std::unique_lock<QMutex> QCoreApplicationPrivate::mutexLockerForTranslator(QTranslator *translator)
{
if (!QCoreApplication::self)
- return false;
+ return std::unique_lock<QMutex>();
+
QCoreApplicationPrivate *d = QCoreApplication::self->d_func();
- QReadLocker locker(&d->translateMutex);
- return d->translators.contains(translator);
+ std::unique_lock<QMutex> locker(d->translateMutex);
+ if (!d->translators.contains(translator))
+ locker.unlock();
+
+ return locker;
}
#else
diff --git a/src/corelib/kernel/qcoreapplication_p.h b/src/corelib/kernel/qcoreapplication_p.h
index 0027b1ad57f..4cb6254e98d 100644
--- a/src/corelib/kernel/qcoreapplication_p.h
+++ b/src/corelib/kernel/qcoreapplication_p.h
@@ -30,9 +30,11 @@
#include "private/qcore_mac_p.h"
#endif
-QT_BEGIN_NAMESPACE
+#ifndef QT_NO_TRANSLATION
+#include <mutex>
+#endif
-typedef QList<QTranslator*> QTranslatorList;
+QT_BEGIN_NAMESPACE
class QAbstractEventDispatcher;
@@ -147,9 +149,9 @@ public:
static bool is_app_closing;
#endif
#ifndef QT_NO_TRANSLATION
- QTranslatorList translators;
- QReadWriteLock translateMutex;
- static bool isTranslatorInstalled(QTranslator *translator);
+ QList<QTranslator*> translators;
+ QMutex translateMutex;
+ static std::unique_lock<QMutex> mutexLockerForTranslator(QTranslator *translator);
#endif
static bool setuidAllowed;
diff --git a/src/corelib/kernel/qtranslator.cpp b/src/corelib/kernel/qtranslator.cpp
index 6b68cb7a513..47483dc6470 100644
--- a/src/corelib/kernel/qtranslator.cpp
+++ b/src/corelib/kernel/qtranslator.cpp
@@ -463,6 +463,12 @@ bool QTranslator::load(const QString & filename, const QString & directory,
const QString & suffix)
{
Q_D(QTranslator);
+
+ std::unique_lock locker = QCoreApplicationPrivate::mutexLockerForTranslator(this);
+ if (locker.owns_lock())
+ QCoreApplication::postEvent(QCoreApplication::instance(),
+ new QEvent(QEvent::LanguageChange));
+
d->clear();
QString prefix;
@@ -738,6 +744,12 @@ bool QTranslator::load(const QLocale & locale,
const QString & suffix)
{
Q_D(QTranslator);
+
+ std::unique_lock locker = QCoreApplicationPrivate::mutexLockerForTranslator(this);
+ if (locker.owns_lock())
+ QCoreApplication::postEvent(QCoreApplication::instance(),
+ new QEvent(QEvent::LanguageChange));
+
d->clear();
return d->load_translation(locale, filename, prefix, directory, suffix);
}
@@ -757,6 +769,12 @@ bool QTranslator::load(const QLocale & locale,
bool QTranslator::load(const uchar *data, int len, const QString &directory)
{
Q_D(QTranslator);
+
+ std::unique_lock locker = QCoreApplicationPrivate::mutexLockerForTranslator(this);
+ if (locker.owns_lock())
+ QCoreApplication::postEvent(QCoreApplication::instance(),
+ new QEvent(QEvent::LanguageChange));
+
d->clear();
if (!data || len < MagicLength || memcmp(data, magic, MagicLength))
@@ -1030,7 +1048,6 @@ searchDependencies:
void QTranslatorPrivate::clear()
{
- Q_Q(QTranslator);
if (unmapPointer && unmapLength) {
#if defined(QT_USE_MMAP)
if (used_mmap) {
@@ -1058,10 +1075,6 @@ void QTranslatorPrivate::clear()
language.clear();
filePath.clear();
-
- if (QCoreApplicationPrivate::isTranslatorInstalled(q))
- QCoreApplication::postEvent(QCoreApplication::instance(),
- new QEvent(QEvent::LanguageChange));
}
/*!