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>
bb10
Edward Welbourne 2021-03-17 15:04:05 +01:00
parent 4dccdd3693
commit 855f8a3f98
2 changed files with 27 additions and 19 deletions

View File

@ -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

View File

@ -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.