diff options
author | Edward Welbourne <edward.welbourne@qt.io> | 2021-03-17 15:04:05 +0100 |
---|---|---|
committer | Edward Welbourne <edward.welbourne@qt.io> | 2021-04-20 16:04:14 +0200 |
commit | 855f8a3f98f366b26eecba556cdfb2e509081a29 (patch) | |
tree | b07747ff9e22db67695610843fae524fefd36912 | |
parent | 4dccdd3693d69fe7030e61ba9b7639c6fc76b97e (diff) |
Handle overflow in QTimeZonePrivate::dataForLocalTime() and its caller
If the final result is outside the representable range, we can only
declare the given date-time invalid.
Change-Id: Ibce09462048bf351199657a5da2c55bb3ce5b934
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
-rw-r--r-- | src/corelib/time/qdatetime.cpp | 43 | ||||
-rw-r--r-- | src/corelib/time/qtimezoneprivate.cpp | 3 |
2 files changed, 27 insertions, 19 deletions
diff --git a/src/corelib/time/qdatetime.cpp b/src/corelib/time/qdatetime.cpp index d61bd3a69b..f627836a46 100644 --- a/src/corelib/time/qdatetime.cpp +++ b/src/corelib/time/qdatetime.cpp @@ -3255,26 +3255,33 @@ inline qint64 QDateTimePrivate::zoneMSecsToEpochMSecs(qint64 zoneMSecs, const QT Q_ASSERT(zone.isValid()); // Get the effective data from QTimeZone QTimeZonePrivate::Data data = zone.d->dataForLocalTime(zoneMSecs, int(hint)); - Q_ASSERT(zone.d->offsetFromUtc(data.atMSecsSinceEpoch) == data.offsetFromUtc); - Q_ASSERT(([data](qint64 offset) { - return offset == data.offsetFromUtc - // When zoneMSecs falls in a spring-forward's gap: - || offset == data.standardTimeOffset - // When it falls in the gap leading into double-DST: - || offset == 2 * data.standardTimeOffset - // When it falls in a skipped day (Pacific date-line crossings): - || (data.offsetFromUtc - offset) % SECS_PER_DAY == 0; - })((zoneMSecs - data.atMSecsSinceEpoch) / MSECS_PER_SEC)); - // Docs state any time before 1970-01-01 will *not* have any DST applied - // but all affected times afterwards will have DST applied. - if (data.atMSecsSinceEpoch < 0) { - msecsToTime(zoneMSecs, zoneDate, zoneTime); - return zoneMSecs - data.standardTimeOffset * MSECS_PER_SEC; + if (data.offsetFromUtc == QTimeZonePrivate::invalidSeconds()) { + if (zoneDate) + *zoneDate = QDate(); + if (zoneTime) + *zoneTime = QTime(); } else { - msecsToTime(data.atMSecsSinceEpoch + data.offsetFromUtc * MSECS_PER_SEC, - zoneDate, zoneTime); - return data.atMSecsSinceEpoch; + Q_ASSERT(zone.d->offsetFromUtc(data.atMSecsSinceEpoch) == data.offsetFromUtc); + Q_ASSERT(([data](qint64 offset) { + return offset == data.offsetFromUtc + // When zoneMSecs falls in a spring-forward's gap: + || offset == data.standardTimeOffset + // When it falls in the gap leading into double-DST: + || offset == 2 * data.standardTimeOffset + // When it falls in a skipped day (Pacific date-line crossings): + || (data.offsetFromUtc - offset) % SECS_PER_DAY == 0; + })((zoneMSecs - data.atMSecsSinceEpoch) / MSECS_PER_SEC)); + // Docs state any time before 1970-01-01 will *not* have any DST applied + // but all affected times afterwards will have DST applied. + if (data.atMSecsSinceEpoch < 0) { + msecsToTime(zoneMSecs, zoneDate, zoneTime); + return zoneMSecs - data.standardTimeOffset * MSECS_PER_SEC; + } else { + msecsToTime(data.atMSecsSinceEpoch + data.offsetFromUtc * MSECS_PER_SEC, + zoneDate, zoneTime); + } } + return data.atMSecsSinceEpoch; } #endif // timezone diff --git a/src/corelib/time/qtimezoneprivate.cpp b/src/corelib/time/qtimezoneprivate.cpp index 9053d12f01..6b49cc3086 100644 --- a/src/corelib/time/qtimezoneprivate.cpp +++ b/src/corelib/time/qtimezoneprivate.cpp @@ -449,7 +449,8 @@ QTimeZonePrivate::Data QTimeZonePrivate::dataForLocalTime(qint64 forLocalMSecs, int early = offsetFromUtc(recent); int late = offsetFromUtc(imminent); if (early == late) { // > 99% of the time - utcEpochMSecs = forLocalMSecs - early * 1000; + if (sub_overflow(forLocalMSecs, early * qint64(1000), &utcEpochMSecs)) + return invalidData(); // Outside representable range } else { // Close to a DST transition: early > late is near a fall-back, // early < late is near a spring-forward. |