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>
bb10
parent
b124171309
commit
b73dafbf86
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue