mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-07 06:25:30 +00:00
ICU-22513 Return error if days is too large in IslamicUmalquraCalendar
If the year is too large it may overflow the int32_t variable and cause slow or infinity loop, return error if the year is too large that the conversion to day may overflow int32_t. Limit the value to max value of int32_t divide by 400.
This commit is contained in:
parent
3d1dee6837
commit
cdab88ff4e
8 changed files with 62 additions and 11 deletions
|
@ -3078,7 +3078,10 @@ void Calendar::computeTime(UErrorCode& status) {
|
|||
}
|
||||
|
||||
// Compute the Julian day
|
||||
int32_t julianDay = computeJulianDay();
|
||||
int32_t julianDay = computeJulianDay(status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
double millis = Grego::julianDayToMillis(julianDay);
|
||||
|
||||
|
@ -3309,7 +3312,7 @@ int32_t Calendar::computeZoneOffset(double millis, double millisInDay, UErrorCod
|
|||
return rawOffset + dstOffset;
|
||||
}
|
||||
|
||||
int32_t Calendar::computeJulianDay()
|
||||
int32_t Calendar::computeJulianDay(UErrorCode &status)
|
||||
{
|
||||
// We want to see if any of the date fields is newer than the
|
||||
// JULIAN_DAY. If not, then we use JULIAN_DAY. If so, then we do
|
||||
|
@ -3333,12 +3336,15 @@ int32_t Calendar::computeJulianDay()
|
|||
bestField = UCAL_DAY_OF_MONTH;
|
||||
}
|
||||
|
||||
return handleComputeJulianDay(bestField);
|
||||
return handleComputeJulianDay(bestField, status);
|
||||
}
|
||||
|
||||
// -------------------------------------------
|
||||
|
||||
int32_t Calendar::handleComputeJulianDay(UCalendarDateFields bestField) {
|
||||
int32_t Calendar::handleComputeJulianDay(UCalendarDateFields bestField, UErrorCode &status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
UBool useMonth = (bestField == UCAL_DAY_OF_MONTH ||
|
||||
bestField == UCAL_WEEK_OF_MONTH ||
|
||||
bestField == UCAL_DAY_OF_WEEK_IN_MONTH);
|
||||
|
@ -3351,6 +3357,12 @@ int32_t Calendar::handleComputeJulianDay(UCalendarDateFields bestField) {
|
|||
}
|
||||
|
||||
internalSet(UCAL_EXTENDED_YEAR, year);
|
||||
// Return U_ILLEGAL_ARGUMENT_ERROR if year is too large that may cuase int32_t overflow
|
||||
// later.
|
||||
if (year > INT32_MAX / 400) {
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined (U_DEBUG_CAL)
|
||||
fprintf(stderr, "%s:%d: bestField= %s - y=%d\n", __FILE__, __LINE__, fldName(bestField), year);
|
||||
|
|
|
@ -472,17 +472,20 @@ GregorianCalendar::isLeapYear(int32_t year) const
|
|||
|
||||
// -------------------------------------
|
||||
|
||||
int32_t GregorianCalendar::handleComputeJulianDay(UCalendarDateFields bestField)
|
||||
int32_t GregorianCalendar::handleComputeJulianDay(UCalendarDateFields bestField, UErrorCode& status)
|
||||
{
|
||||
fInvertGregorian = false;
|
||||
|
||||
int32_t jd = Calendar::handleComputeJulianDay(bestField);
|
||||
int32_t jd = Calendar::handleComputeJulianDay(bestField, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if((bestField == UCAL_WEEK_OF_YEAR) && // if we are doing WOY calculations, we are counting relative to Jan 1 *julian*
|
||||
(internalGet(UCAL_EXTENDED_YEAR)==fGregorianCutoverYear) &&
|
||||
jd >= fCutoverJulianDay) {
|
||||
fInvertGregorian = true; // So that the Julian Jan 1 will be used in handleComputeMonthStart
|
||||
return Calendar::handleComputeJulianDay(bestField);
|
||||
return Calendar::handleComputeJulianDay(bestField, status);
|
||||
}
|
||||
|
||||
|
||||
|
@ -495,7 +498,10 @@ int32_t GregorianCalendar::handleComputeJulianDay(UCalendarDateFields bestField)
|
|||
__FILE__, __LINE__, jd);
|
||||
#endif
|
||||
fInvertGregorian = true;
|
||||
jd = Calendar::handleComputeJulianDay(bestField);
|
||||
jd = Calendar::handleComputeJulianDay(bestField, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
#if defined (U_DEBUG_CAL)
|
||||
fprintf(stderr, "%s:%d: fIsGregorian %s, fInvertGregorian %s - ",
|
||||
__FILE__, __LINE__,fIsGregorian?"T":"F", fInvertGregorian?"T":"F");
|
||||
|
|
|
@ -1704,10 +1704,11 @@ protected:
|
|||
* handleGetMonthLength() to obtain the calendar-specific month
|
||||
* length.
|
||||
* @param bestField which field to use to calculate the date
|
||||
* @param status ICU Error Code
|
||||
* @return julian day specified by calendar fields.
|
||||
* @internal
|
||||
*/
|
||||
virtual int32_t handleComputeJulianDay(UCalendarDateFields bestField);
|
||||
virtual int32_t handleComputeJulianDay(UCalendarDateFields bestField, UErrorCode &status);
|
||||
|
||||
/**
|
||||
* Subclasses must override this to convert from week fields
|
||||
|
@ -1731,10 +1732,11 @@ protected:
|
|||
/**
|
||||
* Compute the Julian day from fields. Will determine whether to use
|
||||
* the JULIAN_DAY field directly, or other fields.
|
||||
* @param status ICU Error Code
|
||||
* @return the julian day
|
||||
* @internal
|
||||
*/
|
||||
int32_t computeJulianDay();
|
||||
int32_t computeJulianDay(UErrorCode &status);
|
||||
|
||||
/**
|
||||
* Compute the milliseconds in the day from the fields. This is a
|
||||
|
|
|
@ -495,10 +495,11 @@ public:
|
|||
* handleGetMonthLength() to obtain the calendar-specific month
|
||||
* length.
|
||||
* @param bestField which field to use to calculate the date
|
||||
* @param status Fill-in parameter which receives the status of this operation.
|
||||
* @return julian day specified by calendar fields.
|
||||
* @internal
|
||||
*/
|
||||
virtual int32_t handleComputeJulianDay(UCalendarDateFields bestField) override;
|
||||
virtual int32_t handleComputeJulianDay(UCalendarDateFields bestField, UErrorCode& status) override;
|
||||
|
||||
/**
|
||||
* Return the number of days in the given month of the given extended
|
||||
|
|
|
@ -105,6 +105,7 @@ void IntlCalendarTest::runIndexedTest( int32_t index, UBool exec, const char* &n
|
|||
TESTCASE_AUTO(TestConsistencyIslamicUmalqura);
|
||||
TESTCASE_AUTO(TestConsistencyPersian);
|
||||
TESTCASE_AUTO(TestConsistencyJapanese);
|
||||
TESTCASE_AUTO(TestIslamicUmalquraCalendarSlow);
|
||||
TESTCASE_AUTO_END;
|
||||
}
|
||||
|
||||
|
@ -1122,6 +1123,18 @@ void IntlCalendarTest::checkConsistency(const char* locale) {
|
|||
}
|
||||
}
|
||||
|
||||
void IntlCalendarTest::TestIslamicUmalquraCalendarSlow() {
|
||||
IcuTestErrorCode status(*this, "TestIslamicUmalquraCalendarSlow");
|
||||
Locale l("th@calendar=islamic-umalqura");
|
||||
std::unique_ptr<Calendar> cal(
|
||||
Calendar::createInstance(l, status));
|
||||
cal->add(UCAL_YEAR, 1229080905, status);
|
||||
cal->roll(UCAL_WEEK_OF_MONTH, 1499050699, status);
|
||||
cal->fieldDifference(0.000000, UCAL_YEAR_WOY, status);
|
||||
// Ignore the error
|
||||
status.reset();
|
||||
}
|
||||
|
||||
void IntlCalendarTest::simpleTest(const Locale& loc, const UnicodeString& expect, UDate expectDate, UErrorCode& status)
|
||||
{
|
||||
UnicodeString tmp;
|
||||
|
|
|
@ -60,6 +60,7 @@ public:
|
|||
void TestConsistencyIslamicUmalqura();
|
||||
void TestConsistencyPersian();
|
||||
void TestConsistencyJapanese();
|
||||
void TestIslamicUmalquraCalendarSlow();
|
||||
|
||||
protected:
|
||||
// Test a Gregorian-Like calendar
|
||||
|
|
|
@ -6233,6 +6233,10 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca
|
|||
|
||||
internalSet(EXTENDED_YEAR, year);
|
||||
|
||||
if (year > Long.MAX_VALUE / 400) {
|
||||
throw new IllegalArgumentException("year is too large");
|
||||
}
|
||||
|
||||
int month = useMonth ? internalGetMonth(getDefaultMonthInYear(year)) : 0;
|
||||
|
||||
// Get the Julian day of the day BEFORE the start of this year.
|
||||
|
|
|
@ -2710,5 +2710,17 @@ public class CalendarRegressionTest extends com.ibm.icu.dev.test.TestFmwk {
|
|||
Calendar.getInstance(Locale.forLanguageTag(localeIds[i])).getFirstDayOfWeek());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void TestIslamicUmalquraCalendarSlow() { // ICU-22513
|
||||
Locale loc = new Locale("th@calendar=islamic-umalqura");
|
||||
Calendar cal = Calendar.getInstance(loc);
|
||||
cal.clear();
|
||||
cal.add(Calendar.YEAR, 1229080905);
|
||||
cal.roll(Calendar.WEEK_OF_MONTH, 1499050699);
|
||||
cal.fieldDifference(new Date(0), Calendar.YEAR_WOY);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
//eof
|
||||
|
|
Loading…
Add table
Reference in a new issue