diff options
author | Marc Mutz <marc.mutz@qt.io> | 2022-01-04 18:03:22 +0100 |
---|---|---|
committer | Marc Mutz <marc.mutz@qt.io> | 2022-01-12 19:37:21 +0000 |
commit | 11becbe910f806570ca9aa6a131b5887303e2a00 (patch) | |
tree | 5b56393aa3d6290d7610ffdf8341c8c469844295 /src/corelib/time | |
parent | bfc713530a6354ce786d3f9bd0f4567844e7240f (diff) |
QTzTimeZonePrivate: fix UB (data race on m_icu)
The fallback m_icu QIcuTimeZonePrivate is lazily constructed, which
means that two threads each with their own copy of a QTimeZone with a
shared QTzTimeZonePrivate will race over who gets to set m_icu,
e.g. when concurrently calling QTimeZone::displayName().
Fix by protecting m_icu with a mutex. For simplicity, use a static
mutex, not a per-instance one (which would delete the
QTzTimeZonePrivate copy constructor, which clone() relies on). This is
sufficient for 5.15. For Qt 6, going forward, we could make this
lock-less, too.
[ChangeLog][QtCore][QTimeZone] Fixed a data race on Unix platforms when
implicitly-shared copies of QTimeZone objects were used in certain ways
(e.g. calling displayName()) from different threads and Qt was
configured with ICU support.
Pick-to: 6.3 6.2 5.15
Change-Id: I7e57aef3dd44a90289ad86d0578ece1e54920730
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Diffstat (limited to 'src/corelib/time')
-rw-r--r-- | src/corelib/time/qtimezoneprivate_tz.cpp | 12 |
1 files changed, 12 insertions, 0 deletions
diff --git a/src/corelib/time/qtimezoneprivate_tz.cpp b/src/corelib/time/qtimezoneprivate_tz.cpp index b23ccfb3b2..8dfd88b281 100644 --- a/src/corelib/time/qtimezoneprivate_tz.cpp +++ b/src/corelib/time/qtimezoneprivate_tz.cpp @@ -42,6 +42,7 @@ #include "qtimezone.h" #include "qtimezoneprivate_p.h" #include "private/qlocale_tools_p.h" +#include "private/qlocking_p.h" #include <QtCore/QDataStream> #include <QtCore/QDateTime> @@ -62,6 +63,10 @@ QT_BEGIN_NAMESPACE +#if QT_CONFIG(icu) +static QBasicMutex s_icu_mutex; +#endif + /* Private @@ -729,6 +734,9 @@ QTzTimeZonePrivate::~QTzTimeZonePrivate() QTzTimeZonePrivate *QTzTimeZonePrivate::clone() const { +#if QT_CONFIG(icu) + const auto lock = qt_scoped_lock(s_icu_mutex); +#endif return new QTzTimeZonePrivate(*this); } @@ -989,12 +997,14 @@ QString QTzTimeZonePrivate::displayName(qint64 atMSecsSinceEpoch, const QLocale &locale) const { #if QT_CONFIG(icu) + auto lock = qt_unique_lock(s_icu_mutex); if (!m_icu) m_icu = new QIcuTimeZonePrivate(m_id); // TODO small risk may not match if tran times differ due to outdated files // TODO Some valid TZ names are not valid ICU names, use translation table? if (m_icu->isValid()) return m_icu->displayName(atMSecsSinceEpoch, nameType, locale); + lock.unlock(); #else Q_UNUSED(nameType); Q_UNUSED(locale); @@ -1008,12 +1018,14 @@ QString QTzTimeZonePrivate::displayName(QTimeZone::TimeType timeType, const QLocale &locale) const { #if QT_CONFIG(icu) + auto lock = qt_unique_lock(s_icu_mutex); if (!m_icu) m_icu = new QIcuTimeZonePrivate(m_id); // TODO small risk may not match if tran times differ due to outdated files // TODO Some valid TZ names are not valid ICU names, use translation table? if (m_icu->isValid()) return m_icu->displayName(timeType, nameType, locale); + lock.unlock(); #else Q_UNUSED(timeType); Q_UNUSED(nameType); |