summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEdward Welbourne <edward.welbourne@qt.io>2021-03-17 15:04:05 +0100
committerEdward Welbourne <edward.welbourne@qt.io>2021-04-20 16:04:14 +0200
commit855f8a3f98f366b26eecba556cdfb2e509081a29 (patch)
treeb07747ff9e22db67695610843fae524fefd36912
parent4dccdd3693d69fe7030e61ba9b7639c6fc76b97e (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.cpp43
-rw-r--r--src/corelib/time/qtimezoneprivate.cpp3
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.