From 73744ea41f03b20a9d6dc6ed09a56781e89dacb4 Mon Sep 17 00:00:00 2001 From: Frank Tang Date: Wed, 28 Feb 2024 19:34:13 -0800 Subject: [PATCH] ICU-22633 Fix overflow cause by large AM PM value Fix https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=66771 --- icu4c/source/i18n/calendar.cpp | 4 +++- icu4c/source/test/intltest/caltest.cpp | 18 ++++++++++++++++++ icu4c/source/test/intltest/caltest.h | 1 + 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/icu4c/source/i18n/calendar.cpp b/icu4c/source/i18n/calendar.cpp index 03af659042dd..b0ab6c5526dc 100644 --- a/icu4c/source/i18n/calendar.cpp +++ b/icu4c/source/i18n/calendar.cpp @@ -3279,7 +3279,9 @@ double Calendar::computeMillisInDay() { // Don't normalize here; let overflow bump into the next period. // This is consistent with how we handle other fields. millisInDay += internalGet(UCAL_HOUR); - millisInDay += 12 * internalGet(UCAL_AM_PM); // Default works for unset AM_PM + // Treat even number as AM and odd nubmber as PM to align with the + // logic in roll() + millisInDay += (internalGet(UCAL_AM_PM) % 2 == 0) ? 0 : 12; } } diff --git a/icu4c/source/test/intltest/caltest.cpp b/icu4c/source/test/intltest/caltest.cpp index 13aa985f88be..884f869bfdf9 100644 --- a/icu4c/source/test/intltest/caltest.cpp +++ b/icu4c/source/test/intltest/caltest.cpp @@ -195,6 +195,7 @@ void CalendarTest::runIndexedTest( int32_t index, UBool exec, const char* &name, TESTCASE_AUTO(Test22633IndianOverflow); TESTCASE_AUTO(Test22633IslamicUmalquraOverflow); TESTCASE_AUTO(Test22633PersianOverflow); + TESTCASE_AUTO(Test22633AMPMOverflow); TESTCASE_AUTO(TestAddOverflow); @@ -5677,6 +5678,23 @@ void CalendarTest::Test22633PersianOverflow() { UCAL_YEAR, status); assertFalse("Should not return success", U_SUCCESS(status)); } +void CalendarTest::Test22633AMPMOverflow() { + UErrorCode status = U_ZERO_ERROR; + LocalPointer cal(Calendar::createInstance(Locale("en"), status), status); + U_ASSERT(U_SUCCESS(status)); + cal->setTimeZone(*TimeZone::getGMT()); + cal->clear(); + // Test to set a value > limit should not cause internal overflow. + cal->set(UCAL_AM_PM, 370633137); + assertEquals("set large odd value for UCAL_AM_PM should be treated as PM", + 12.0 * 60.0 * 60.0 *1000.0, cal->getTime(status)); + assertTrue("Should return success", U_SUCCESS(status)); + + cal->set(UCAL_AM_PM, 370633138); + assertEquals("set large even value for UCAL_AM_PM should be treated as AM", + 0.0, cal->getTime(status)); + assertTrue("Should return success", U_SUCCESS(status)); +} void CalendarTest::TestChineseCalendarComputeMonthStart() { // ICU-22639 UErrorCode status = U_ZERO_ERROR; diff --git a/icu4c/source/test/intltest/caltest.h b/icu4c/source/test/intltest/caltest.h index 67fe03869538..2e8b859a1be1 100644 --- a/icu4c/source/test/intltest/caltest.h +++ b/icu4c/source/test/intltest/caltest.h @@ -338,6 +338,7 @@ class CalendarTest: public CalendarTimeZoneTest { void Test22633IndianOverflow(); void Test22633IslamicUmalquraOverflow(); void Test22633PersianOverflow(); + void Test22633AMPMOverflow(); void verifyFirstDayOfWeek(const char* locale, UCalendarDaysOfWeek expected); void TestFirstDayOfWeek();