QDateTime: Fix clearing the ShortData flag in setMSecsSinceEpoch

Unlike setTimeSpec, this forgot to clear the bit when detaching. So it's
possible that some further use of the flags could incorrectly conclude
that the data was short and then proceed to corrupt the pointer.

The example from QTBUG-59061 caused this because toUTC() -> toTimeSpec()
calls setMSecsSinceEpoch which left the bit set; then addDays() calls
setDateTime(), which calls checkValidDateTime() and that corrupted the
pointer. This problem was more visible on 32-bit systems because no
QDateTime was short (except for default constructed ones), but it
can happen on 64-bit with sufficiently large dates.

Task-number: QTBUG-59061
Change-Id: Ibc5c715fda334a75bd2efffd14a562a375a4e69b
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
Thiago Macieira 2017-02-21 11:01:46 -08:00
parent 4d3781b640
commit 07fffa6010
2 changed files with 27 additions and 1 deletions

View File

@ -2842,6 +2842,9 @@ inline bool QDateTime::Data::isShort() const
{
bool b = quintptr(d) & QDateTimePrivate::ShortData;
// sanity check:
Q_ASSERT(b || (d->m_status & QDateTimePrivate::ShortData) == 0);
// even if CanBeSmall = false, we have short data for a default-constructed
// QDateTime object. But it's unlikely.
if (CanBeSmall)
@ -3658,7 +3661,7 @@ void QDateTime::setMSecsSinceEpoch(qint64 msecs)
d.data.status = status;
} else {
d.detach();
d->m_status = status;
d->m_status = status & ~QDateTimePrivate::ShortData;
d->m_msecs = msecs;
}

View File

@ -667,6 +667,29 @@ void tst_QDateTime::setMSecsSinceEpoch()
QCOMPARE(dt.time(), utc.time());
QCOMPARE(dt.timeSpec(), Qt::UTC);
{
QDateTime dt1 = QDateTime::fromMSecsSinceEpoch(msecs, Qt::UTC);
QCOMPARE(dt1, utc);
QCOMPARE(dt1.date(), utc.date());
QCOMPARE(dt1.time(), utc.time());
QCOMPARE(dt1.timeSpec(), Qt::UTC);
}
{
QDateTime dt1(utc.date(), utc.time(), Qt::UTC);
QCOMPARE(dt1, utc);
QCOMPARE(dt1.date(), utc.date());
QCOMPARE(dt1.time(), utc.time());
QCOMPARE(dt1.timeSpec(), Qt::UTC);
}
{
// used to fail to clear the ShortData bit, causing corruption
QDateTime dt1 = dt.addDays(0);
QCOMPARE(dt1, utc);
QCOMPARE(dt1.date(), utc.date());
QCOMPARE(dt1.time(), utc.time());
QCOMPARE(dt1.timeSpec(), Qt::UTC);
}
if (zoneIsCET) {
QCOMPARE(dt.toLocalTime(), cet);