ICU-22633 Fix hang on large negative day in hebrew calendar

Check error status and return error early in the loop
This commit is contained in:
Frank Tang 2024-03-19 01:38:53 -07:00 committed by Frank Yung-Fong Tang
parent 7c22ff7541
commit 6b67715a94
4 changed files with 32 additions and 1 deletions

View file

@ -2368,6 +2368,7 @@ int32_t Calendar::fieldDifference(UDate targetMs, UCalendarDateFields field, UEr
__FILE__, __LINE__, fldName(field));
#endif
ec = U_ILLEGAL_ARGUMENT_ERROR;
return 0;
}
}
// Do a binary search
@ -2405,6 +2406,7 @@ int32_t Calendar::fieldDifference(UDate targetMs, UCalendarDateFields field, UEr
__FILE__, __LINE__, fldName(field));
#endif
ec = U_ILLEGAL_ARGUMENT_ERROR;
return 0;
}
}
}

View file

@ -420,6 +420,9 @@ int32_t HebrewCalendar::startOfYear(int32_t year, UErrorCode &status)
{
ucln_i18n_registerCleanup(UCLN_I18N_HEBREW_CALENDAR, calendar_hebrew_cleanup);
int64_t day = CalendarCache::get(&gCache, year, status);
if(U_FAILURE(status)) {
return 0;
}
if (day == 0) {
// # of months before year
@ -533,7 +536,10 @@ int32_t HebrewCalendar::handleGetLimit(UCalendarDateFields field, ELimitType lim
* Returns the length of the given month in the given year
* @internal
*/
int32_t HebrewCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month, UErrorCode& /* status */) const {
int32_t HebrewCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month, UErrorCode& status) const {
if(U_FAILURE(status)) {
return 0;
}
// Resolve out-of-range months. This is necessary in order to
// obtain the correct year. We correct to
// a 12- or 13-month year (add/subtract 12 or 13, depending
@ -606,16 +612,25 @@ void HebrewCalendar::validateField(UCalendarDateFields field, UErrorCode &status
* @internal
*/
void HebrewCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status) {
if (U_FAILURE(status)) {
return;
}
int32_t d = julianDay - 347997;
double m = ClockMath::floorDivide((d * (double)DAY_PARTS), (double) MONTH_PARTS); // Months (approx)
int32_t year = (int32_t)(ClockMath::floorDivide((19. * m + 234.), 235.) + 1.); // Years (approx)
int32_t ys = startOfYear(year, status); // 1st day of year
if (U_FAILURE(status)) {
return;
}
int32_t dayOfYear = (d - ys);
// Because of the postponement rules, it's possible to guess wrong. Fix it.
while (dayOfYear < 1) {
year--;
ys = startOfYear(year, status);
if (U_FAILURE(status)) {
return;
}
dayOfYear = (d - ys);
}

View file

@ -204,6 +204,8 @@ void CalendarTest::runIndexedTest( int32_t index, UBool exec, const char* &name,
TESTCASE_AUTO(Test22633AddTwiceGetTimeOverflow);
TESTCASE_AUTO(Test22633RollTwiceGetTimeOverflow);
TESTCASE_AUTO(Test22633HebrewLargeNegativeDay);
TESTCASE_AUTO(TestAddOverflow);
@ -5863,6 +5865,17 @@ void CalendarTest::TestChineseCalendarComputeMonthStart() { // ICU-22639
chinese.hasLeapMonthBetweenWinterSolstices);
}
void CalendarTest::Test22633HebrewLargeNegativeDay() {
UErrorCode status = U_ZERO_ERROR;
LocalPointer<Calendar> calendar(
Calendar::createInstance(Locale("en-u-ca-hebrew"), status),
status);
calendar->clear();
calendar->set(UCAL_DAY_OF_YEAR, -2147483648);
calendar->get(UCAL_HOUR, status);
assertEquals("status return without hang", status, U_ILLEGAL_ARGUMENT_ERROR);
}
void CalendarTest::TestAddOverflow() {
UErrorCode status = U_ZERO_ERROR;

View file

@ -352,6 +352,7 @@ public: // package
void TestFirstDayOfWeek();
void TestChineseCalendarComputeMonthStart();
void Test22633HebrewLargeNegativeDay();
void RunChineseCalendarInTemporalLeapYearTest(Calendar* cal);
void RunIslamicCalendarInTemporalLeapYearTest(Calendar* cal);