diff options
author | Edward Welbourne <edward.welbourne@qt.io> | 2023-02-14 14:02:58 +0100 |
---|---|---|
committer | Edward Welbourne <edward.welbourne@qt.io> | 2023-02-20 18:30:44 +0100 |
commit | b73dafbf86f14c6559f663eeb8b2b0aab6cdc297 (patch) | |
tree | ade03f372dd51b63d9ca6ce8e54a13eac8df32a3 /src | |
parent | b124171309b259d429bd064fe3bfdec148869ef4 (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.cpp | 29 | ||||
-rw-r--r-- | src/corelib/global/qtenvironmentvariables_p.h | 1 | ||||
-rw-r--r-- | src/corelib/time/qdatetimeparser.cpp | 17 | ||||
-rw-r--r-- | src/corelib/time/qdatetimeparser_p.h | 2 | ||||
-rw-r--r-- | src/corelib/time/qlocaltime.cpp | 38 |
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) |