summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEdward Welbourne <edward.welbourne@qt.io>2023-02-14 14:02:58 +0100
committerEdward Welbourne <edward.welbourne@qt.io>2023-02-20 18:30:44 +0100
commitb73dafbf86f14c6559f663eeb8b2b0aab6cdc297 (patch)
treeade03f372dd51b63d9ca6ce8e54a13eac8df32a3 /src
parentb124171309b259d429bd064fe3bfdec148869ef4 (diff)
Move access to tzname[] to under the env.var access log
Replace qlocaltime.cpp's qt_tzname() with qTzName() in qtenvironmentvariables{_p.h,.cpp} so as to put the access to the standard library global under the control of the same lock as controls all Qt's calls to tzset() and functions that behave as if they called it. This avoids UB on access to the global during a call to any of these functions. Take care to use the lock only for the shortest time needed. This simplifies both callers and lets a QDTParser method escape to qdatetimeparser.cpp to become a simple local static function instead of a class method defined in a separate compilation unit. Change-Id: I5ddee5641f2ed7b5676ece10375a1d5232eb7f22 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src')
-rw-r--r--src/corelib/global/qtenvironmentvariables.cpp29
-rw-r--r--src/corelib/global/qtenvironmentvariables_p.h1
-rw-r--r--src/corelib/time/qdatetimeparser.cpp17
-rw-r--r--src/corelib/time/qdatetimeparser_p.h2
-rw-r--r--src/corelib/time/qlocaltime.cpp38
5 files changed, 47 insertions, 40 deletions
diff --git a/src/corelib/global/qtenvironmentvariables.cpp b/src/corelib/global/qtenvironmentvariables.cpp
index 4f2a263cc4..6a501bb8c4 100644
--- a/src/corelib/global/qtenvironmentvariables.cpp
+++ b/src/corelib/global/qtenvironmentvariables.cpp
@@ -392,4 +392,33 @@ bool qLocalTime(time_t utc, struct tm *local)
#endif
}
+/* Access to the tzname[] global in one thread is UB if any other is calling
+ tzset() or anything that behaves as if it called tzset(). So also lock this
+ access to prevent such collisions.
+
+ Parameter dstIndex must be 1 for DST or 0 for standard time.
+ Returns the relevant form of the name of local-time's zone.
+*/
+QString qTzName(int dstIndex)
+{
+ char name[512];
+ bool ok;
+#if defined(Q_CC_MSVC)
+ size_t s = 0;
+ {
+ const auto locker = qt_scoped_lock(environmentMutex);
+ ok = _get_tzname(&s, name, 512, dstIndex) != 0;
+ }
+#else
+ {
+ const auto locker = qt_scoped_lock(environmentMutex);
+ const char *const src = tzname[dstIndex];
+ ok = src != nullptr;
+ if (ok)
+ memcpy(name, src, std::min(sizeof(name), strlen(src) + 1));
+ }
+#endif // Q_OS_WIN
+ return ok ? QString::fromLocal8Bit(name) : QString();
+}
+
QT_END_NAMESPACE
diff --git a/src/corelib/global/qtenvironmentvariables_p.h b/src/corelib/global/qtenvironmentvariables_p.h
index afc3c5f52a..0c81d36db6 100644
--- a/src/corelib/global/qtenvironmentvariables_p.h
+++ b/src/corelib/global/qtenvironmentvariables_p.h
@@ -31,6 +31,7 @@ QT_BEGIN_NAMESPACE
Q_CORE_EXPORT void qTzSet();
Q_CORE_EXPORT time_t qMkTime(struct tm *when);
Q_CORE_EXPORT bool qLocalTime(time_t utc, struct tm *local);
+Q_CORE_EXPORT QString qTzName(int dstIndex);
QT_END_NAMESPACE
diff --git a/src/corelib/time/qdatetimeparser.cpp b/src/corelib/time/qdatetimeparser.cpp
index c4e4ddbef7..b8fbb7e03a 100644
--- a/src/corelib/time/qdatetimeparser.cpp
+++ b/src/corelib/time/qdatetimeparser.cpp
@@ -3,7 +3,6 @@
#include "qplatformdefs.h"
#include "private/qdatetimeparser_p.h"
-#include "private/qstringiterator_p.h"
#include "qdatastream.h"
#include "qdatetime.h"
@@ -13,6 +12,9 @@
#include "qtimezone.h"
#include "qvarlengtharray.h"
+#include "private/qstringiterator_p.h"
+#include "private/qtenvironmentvariables_p.h"
+
//#define QDATETIMEPARSER_DEBUG
#if defined (QDATETIMEPARSER_DEBUG) && !defined(QT_NO_DEBUG_STREAM)
# define QDTPDEBUG qDebug()
@@ -1140,6 +1142,19 @@ static QTime actualTime(QDateTimeParser::Sections known,
return actual;
}
+/*
+ \internal
+*/
+static int startsWithLocalTimeZone(QStringView name)
+{
+ for (int i = 0; i < 2; ++i) {
+ const QString zone(qTzName(i));
+ if (name.startsWith(zone))
+ return zone.size();
+ }
+ return 0;
+}
+
/*!
\internal
*/
diff --git a/src/corelib/time/qdatetimeparser_p.h b/src/corelib/time/qdatetimeparser_p.h
index 4c39f4b951..64ced268c9 100644
--- a/src/corelib/time/qdatetimeparser_p.h
+++ b/src/corelib/time/qdatetimeparser_p.h
@@ -177,8 +177,6 @@ private:
ParsedSection findTimeZoneName(QStringView str, const QDateTime &when) const;
ParsedSection findTimeZone(QStringView str, const QDateTime &when,
int maxVal, int minVal, int mode) const;
- // Implemented in qlocaltime.cpp:
- static int startsWithLocalTimeZone(const QStringView name);
enum AmPmFinder {
Neither = -1,
diff --git a/src/corelib/time/qlocaltime.cpp b/src/corelib/time/qlocaltime.cpp
index 60df487af6..3b9a236ccf 100644
--- a/src/corelib/time/qlocaltime.cpp
+++ b/src/corelib/time/qlocaltime.cpp
@@ -165,43 +165,8 @@ struct tm timeToTm(qint64 localDay, int secs, QDateTimePrivate::DaylightStatus d
return local;
}
-// Returns the tzname, assume tzset has been called already
-QString qt_tzname(QDateTimePrivate::DaylightStatus daylightStatus)
-{
- int isDst = (daylightStatus == QDateTimePrivate::DaylightTime) ? 1 : 0;
-#if defined(Q_CC_MSVC)
- size_t s = 0;
- char name[512];
- if (_get_tzname(&s, name, 512, isDst))
- return QString();
- return QString::fromLocal8Bit(name);
-#else
- return QString::fromLocal8Bit(tzname[isDst]);
-#endif // Q_OS_WIN
-}
-
} // namespace
-#if QT_CONFIG(datetimeparser)
-/*
- \internal
- Implemented here to share qt_tzname()
-*/
-int QDateTimeParser::startsWithLocalTimeZone(QStringView name)
-{
- QDateTimePrivate::DaylightStatus zones[2] = {
- QDateTimePrivate::StandardTime,
- QDateTimePrivate::DaylightTime
- };
- for (const auto z : zones) {
- QString zone(qt_tzname(z));
- if (name.startsWith(zone))
- return zone.size();
- }
- return 0;
-}
-#endif // datetimeparser
-
namespace QLocalTime {
#ifndef QT_BOOTSTRAPPED
@@ -319,8 +284,7 @@ QString localTimeAbbbreviationAt(qint64 local, QDateTimePrivate::DaylightStatus
time_t utcSecs;
if (!callMkTime(&tmLocal, &utcSecs))
return {};
- return qt_tzname(tmLocal.tm_isdst > 0 ? QDateTimePrivate::DaylightTime
- : QDateTimePrivate::StandardTime);
+ return qTzName(tmLocal.tm_isdst > 0 ? 1 : 0);
}
QDateTimePrivate::ZoneState mapLocalTime(qint64 local, QDateTimePrivate::DaylightStatus dst)