ICU-13538 in ICU4C Islamic cal, use int64_t math for one operation to avoid overflow; add tests in C and J

X-SVN-Rev: 40882
This commit is contained in:
Peter Edberg 2018-02-09 19:31:12 +00:00
parent ba8b599ab5
commit 64aa4beb28
4 changed files with 57 additions and 4 deletions

View File

@ -614,7 +614,7 @@ void IslamicCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status)
days = julianDay - ASTRONOMICAL_EPOC;
}
// Use the civil calendar approximation, which is just arithmetic
year = (int)ClockMath::floorDivide( (double)(30 * days + 10646) , 10631.0 );
year = (int32_t)ClockMath::floorDivide(30 * (int64_t)days + 10646, (int64_t)10631);
month = (int32_t)uprv_ceil((days - 29 - yearStart(year)) / 29.5 );
month = month<11?month:11;
startDate = monthStart(year, month);

View File

@ -93,6 +93,7 @@ CalendarRegressionTest::runIndexedTest( int32_t index, UBool exec, const char* &
CASE(50,TestT9452);
CASE(51,TestT11632);
CASE(52,TestPersianCalOverflow);
CASE(53,TestIslamicCalOverflow);
default: name = ""; break;
}
}
@ -3009,9 +3010,9 @@ void CalendarRegressionTest::TestPersianCalOverflow(void) {
month = cal->get(UCAL_MONTH, status);
dayOfMonth = cal->get(UCAL_DATE, status);
if ( U_FAILURE(status) ) {
errln("FAIL: Calendar->get MONTH/DATE for localeID %s, julianDay %d, status %s\n", localeID, jd, u_errorName(status));
errln("FAIL: Calendar->get MONTH/DATE for localeID %s, julianDay %d, status %s", localeID, jd, u_errorName(status));
} else if (month > maxMonth || dayOfMonth > maxDayOfMonth) {
errln("FAIL: localeID %s, julianDay %d; maxMonth %d, got month %d; maxDayOfMonth %d, got dayOfMonth %d\n",
errln("FAIL: localeID %s, julianDay %d; maxMonth %d, got month %d; maxDayOfMonth %d, got dayOfMonth %d",
localeID, jd, maxMonth, month, maxDayOfMonth, dayOfMonth);
}
}
@ -3019,4 +3020,35 @@ void CalendarRegressionTest::TestPersianCalOverflow(void) {
}
}
/**
* @bug tickets 12661, 13538
*/
void CalendarRegressionTest::TestIslamicCalOverflow(void) {
const char* localeID = "ar@calendar=islamic-civil";
UErrorCode status = U_ZERO_ERROR;
Calendar* cal = Calendar::createInstance(Locale(localeID), status);
if(U_FAILURE(status)) {
dataerrln("FAIL: Calendar::createInstance for localeID %s: %s", localeID, u_errorName(status));
} else {
int32_t maxMonth = cal->getMaximum(UCAL_MONTH);
int32_t maxDayOfMonth = cal->getMaximum(UCAL_DATE);
int32_t jd, year, month, dayOfMonth;
for (jd = 73530872; jd <= 73530876; jd++) { // year 202002, int32_t overflow if jd >= 73530874
status = U_ZERO_ERROR;
cal->clear();
cal->set(UCAL_JULIAN_DAY, jd);
year = cal->get(UCAL_YEAR, status);
month = cal->get(UCAL_MONTH, status);
dayOfMonth = cal->get(UCAL_DATE, status);
if ( U_FAILURE(status) ) {
errln("FAIL: Calendar->get YEAR/MONTH/DATE for localeID %s, julianDay %d, status %s", localeID, jd, u_errorName(status));
} else if (month > maxMonth || dayOfMonth > maxDayOfMonth) {
errln("FAIL: localeID %s, julianDay %d; got year %d; maxMonth %d, got month %d; maxDayOfMonth %d, got dayOfMonth %d",
localeID, jd, year, maxMonth, month, maxDayOfMonth, dayOfMonth);
}
}
delete cal;
}
}
#endif /* #if !UCONFIG_NO_FORMATTING */

View File

@ -79,6 +79,7 @@ public:
void TestT9452(void);
void TestT11632(void);
void TestPersianCalOverflow(void);
void TestIslamicCalOverflow(void);
void printdate(GregorianCalendar *cal, const char *string);
void dowTest(UBool lenient) ;

View File

@ -2521,5 +2521,25 @@ public class CalendarRegressionTest extends com.ibm.icu.dev.test.TestFmwk {
}
}
}
}
@Test
public void TestIslamicCalOverflow() {
String localeID = "ar@calendar=islamic-civil";
Calendar cal = Calendar.getInstance(new ULocale(localeID));
int maxMonth = cal.getMaximum(Calendar.MONTH);
int maxDayOfMonth = cal.getMaximum(Calendar.DATE);
int jd, year, month, dayOfMonth;
for (jd = 73530872; jd <= 73530876; jd++) { // year 202002, int32_t overflow if jd >= 73530874
cal.clear();
cal.set(Calendar.JULIAN_DAY, jd);
year = cal.get(Calendar.YEAR);
month = cal.get(Calendar.MONTH);
dayOfMonth = cal.get(Calendar.DATE);
if (month > maxMonth || dayOfMonth > maxDayOfMonth) {
errln("Error: localeID " + localeID + ", julianDay " + jd + "; got year " + year + "; maxMonth " + maxMonth +
", got month " + month + "; maxDayOfMonth " + maxDayOfMonth + ", got dayOfMonth " + dayOfMonth);
}
}
}
}
//eof