summaryrefslogtreecommitdiffstats
path: root/src/corelib/text/qlocale.cpp
diff options
context:
space:
mode:
authorEdward Welbourne <edward.welbourne@qt.io>2023-07-19 15:14:31 +0200
committerEdward Welbourne <edward.welbourne@qt.io>2023-07-31 17:16:14 +0200
commit2e9d33e5344c75d0b91307aebe2bfa2fded1268f (patch)
treed6cc4a190347cad4280a125933cd4c3b87ed4ee2 /src/corelib/text/qlocale.cpp
parentebb361ee3f02d677460fc2b55a47c6cd4bbbc489 (diff)
Use correct index for QLocale::system()'s static
Nothing prevents client code from calling QLocale::setDefault() before we ever instantiate QLocale::system() - aside from some quirks that mean setDefault(), currently, does instantiate QLocale::system() to force initialization of defaultLocalePrivate - so using defaultIndex() could set the system QLocalePrivate instance's index incorrectly. In any case, even if the index is initially set correctly, a subsequent change to the system locale would change the correct index; and nothing outside QLocale::system() has access to the instance that would then be remembering an out-of-date index. Actually tripping over that inconsistency took some deviousness, but was possible. The index is (currently) only used for month name lookups and those special-case, for the Roman-derived calendars, the system locale, to only use the index if the system locale offers no name for a month. Meanwhile, updateSystemPrivate() uses the fallback locale's index for its look-up of which CLDR data to copy into the fallback QLocaleData for the system locale. None the less, a non-Roman calendar's lookup will go via the index to get at the CLDR data for that calendar, thereby exposing the system locale's index to use; and, sure enough, a setDefault() could lead that to produce wrong answers. In QLocale::system() there's a cached QLocalePrivate, whose index we need to ensure stays in sync with the active system locale. So pass its &m_index to systemData(), which will now (when passed this) ensure it's up to date. Since we always have called systemData(), to ensure it is up to date, we can skip that update in the initialization of the cached private and use m_index = -1 to let systemData() know when it's in the initial call, thereby making the static cache constinit. Amended a test to what proved the issue was present. Change-Id: I8d7ab5830cf0bbb9265c2af2a1edc9396ddef79f Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Diffstat (limited to 'src/corelib/text/qlocale.cpp')
-rw-r--r--src/corelib/text/qlocale.cpp40
1 files changed, 34 insertions, 6 deletions
diff --git a/src/corelib/text/qlocale.cpp b/src/corelib/text/qlocale.cpp
index d15bdd93cd..c7ecddb484 100644
--- a/src/corelib/text/qlocale.cpp
+++ b/src/corelib/text/qlocale.cpp
@@ -788,25 +788,42 @@ static void updateSystemPrivate()
}
#endif // !QT_NO_SYSTEMLOCALE
-static const QLocaleData *systemData()
+static const QLocaleData *systemData(qsizetype *sysIndex = nullptr)
{
#ifndef QT_NO_SYSTEMLOCALE
/*
Copy over the information from the fallback locale and modify.
- This modifies (cross-thread) global state, so take care to only call it in
- one thread.
+ If sysIndex is passed, it should be the m_index of the system locale's
+ QLocalePrivate, which we'll update if it needs it.
+
+ This modifies (cross-thread) global state, so is mutex-protected.
*/
{
+ Q_CONSTINIT static QLocaleId sysId;
+ bool updated = false;
+
Q_CONSTINIT static QBasicMutex systemDataMutex;
systemDataMutex.lock();
- if (systemLocaleData.m_language_id == 0)
+ if (systemLocaleData.m_language_id == 0) {
updateSystemPrivate();
+ updated = true;
+ }
+ // Initialization of system private has *sysIndex == -1 to hit this.
+ if (sysIndex && (updated || *sysIndex < 0)) {
+ const QLocaleId nowId = systemLocaleData.id();
+ if (sysId != nowId || *sysIndex < 0) {
+ // This look-up may be expensive:
+ *sysIndex = QLocaleData::findLocaleIndex(nowId);
+ sysId = nowId;
+ }
+ }
systemDataMutex.unlock();
}
return &systemLocaleData;
#else
+ Q_UNUSED(sysIndex);
return locale_data;
#endif
}
@@ -2749,8 +2766,19 @@ QString QLocale::toString(double f, char format, int precision) const
QLocale QLocale::system()
{
- QT_PREPEND_NAMESPACE(systemData)(); // Ensure system data is up to date.
- static QLocalePrivate locale(systemData(), defaultIndex(), DefaultNumberOptions, 1);
+ constexpr auto sysData = []() {
+ // Same return as systemData(), but leave the setup to the actual call to it.
+#ifdef QT_NO_SYSTEMLOCALE
+ return locale_data;
+#else
+ return &systemLocaleData;
+#endif
+ };
+ Q_CONSTINIT static QLocalePrivate locale(sysData(), -1, DefaultNumberOptions, 1);
+ // Calling systemData() ensures system data is up to date; we also need it
+ // to ensure that locale's index stays up to date:
+ systemData(&locale.m_index);
+ Q_ASSERT(locale.m_index >= 0 && locale.m_index < locale_data_size);
return QLocale(locale);
}