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)