diff --git a/src/corelib/time/qdatetime.cpp b/src/corelib/time/qdatetime.cpp index c3b72073ec..ba00ffc6b7 100644 --- a/src/corelib/time/qdatetime.cpp +++ b/src/corelib/time/qdatetime.cpp @@ -2451,6 +2451,14 @@ static QTime msecsToTime(qint64 msecs) return QTime::fromMSecsSinceStartOfDay(QRoundingDown::qMod(msecs, MSECS_PER_DAY)); } +// True if combining days with millis overflows; otherwise, stores result in *sumMillis +// The inputs should not have opposite signs. +static inline bool daysAndMillisOverflow(qint64 days, qint64 millisInDay, qint64 *sumMillis) +{ + return mul_overflow(days, std::integral_constant(), sumMillis) + || add_overflow(*sumMillis, millisInDay, sumMillis); +} + // Converts a date/time value into msecs static qint64 timeToMSecs(QDate date, QTime time) { @@ -2460,8 +2468,7 @@ static qint64 timeToMSecs(QDate date, QTime time) ++days; dayms -= MSECS_PER_DAY; } - if (mul_overflow(days, std::integral_constant(), &msecs) - || add_overflow(msecs, dayms, &msecs)) { + if (daysAndMillisOverflow(days, dayms, &msecs)) { using Bound = std::numeric_limits; return days < 0 ? Bound::min() : Bound::max(); } @@ -2584,13 +2591,11 @@ static auto millisToWithinRange(qint64 millis) qint64 shifted = 0; bool good = false; } result; - qint64 jd = msecsToJulianDay(millis), fakeJd, diffMillis; + qint64 jd = msecsToJulianDay(millis), fakeJd; auto ymd = QGregorianCalendar::partsFromJulian(jd); result.good = QGregorianCalendar::julianFromParts(systemTimeYearMatching(ymd.year), ymd.month, ymd.day, &fakeJd) - && !mul_overflow(fakeJd - jd, std::integral_constant(), - &diffMillis) - && !add_overflow(diffMillis, millis, &result.shifted); + && !daysAndMillisOverflow(fakeJd - jd, millis, &result.shifted); return result; } @@ -2951,8 +2956,7 @@ static void setDateTime(QDateTimeData &d, QDate date, QTime time) // Check in representable range: qint64 msecs = 0; - if (mul_overflow(days, std::integral_constant(), &msecs) - || add_overflow(msecs, qint64(ds), &msecs)) { + if (daysAndMillisOverflow(days, qint64(ds), &msecs)) { newStatus = QDateTimePrivate::StatusFlags{}; msecs = 0; } diff --git a/src/corelib/time/qlocaltime.cpp b/src/corelib/time/qlocaltime.cpp index e9721f5c8b..2081b16753 100644 --- a/src/corelib/time/qlocaltime.cpp +++ b/src/corelib/time/qlocaltime.cpp @@ -283,6 +283,24 @@ int getUtcOffset(qint64 atMSecsSinceEpoch) } #endif // QT_BOOTSTRAPPED +#define IC(N) std::integral_constant() + +// True if combining day and seconds overflows qint64; otherwise, sets *epochSeconds +inline bool daysAndSecondsOverflow(qint64 julianDay, qint64 daySeconds, qint64 *epochSeconds) +{ + return mul_overflow(julianDay - JULIAN_DAY_FOR_EPOCH, IC(SECS_PER_DAY), epochSeconds) + || add_overflow(*epochSeconds, daySeconds, epochSeconds); +} + +// True if combining seconds and millis overflows; otherwise sets *epochMillis +inline bool secondsAndMillisOverflow(qint64 epochSeconds, qint64 millis, qint64 *epochMillis) +{ + return mul_overflow(epochSeconds, IC(MSECS_PER_SEC), epochMillis) + || add_overflow(*epochMillis, millis, epochMillis); +} + +#undef IC + // Calls the platform variant of localtime() for the given utcMillis, and // returns the local milliseconds, offset from UTC and DST status. QDateTimePrivate::ZoneState utcToLocal(qint64 utcMillis) @@ -306,13 +324,8 @@ QDateTimePrivate::ZoneState utcToLocal(qint64 utcMillis) const qint64 daySeconds = tmSecsWithinDay(local); Q_ASSERT(0 <= daySeconds && daySeconds < SECS_PER_DAY); qint64 localSeconds, localMillis; - if (Q_UNLIKELY( - mul_overflow(jd - JULIAN_DAY_FOR_EPOCH, std::integral_constant(), - &localSeconds) - || add_overflow(localSeconds, daySeconds, &localSeconds) - || mul_overflow(localSeconds, std::integral_constant(), - &localMillis) - || add_overflow(localMillis, qint64(msec), &localMillis))) { + if (Q_UNLIKELY(daysAndSecondsOverflow(jd, daySeconds, &localSeconds) + || secondsAndMillisOverflow(localSeconds, qint64(msec), &localMillis))) { return {utcMillis}; } const auto dst @@ -362,11 +375,9 @@ QDateTimePrivate::ZoneState mapLocalTime(qint64 local, QDateTimePrivate::Dayligh daySecs -= SECS_PER_DAY; } qint64 localSecs; - if (Q_UNLIKELY(mul_overflow(jd - JULIAN_DAY_FOR_EPOCH, - std::integral_constant(), &localSecs) - || add_overflow(localSecs, daySecs, &localSecs))) { + if (Q_UNLIKELY(daysAndSecondsOverflow(jd, daySecs, &localSecs))) return {local, offset, dst, false}; - } + offset = localSecs - utcSecs; if (localSecs < 0 && millis > 0) { @@ -374,9 +385,7 @@ QDateTimePrivate::ZoneState mapLocalTime(qint64 local, QDateTimePrivate::Dayligh millis -= MSECS_PER_SEC; } qint64 revised; - const bool overflow = - mul_overflow(localSecs, std::integral_constant(), &revised) - || add_overflow(revised, millis, &revised); + const bool overflow = secondsAndMillisOverflow(localSecs, millis, &revised); return {overflow ? local : revised, offset, dst, !overflow}; }