]> granicus.if.org Git - icu/commitdiff
ICU-13538 in ICU4C Islamic cal, use int64_t math for one operation to avoid overflow...
authorPeter Edberg <pedberg@unicode.org>
Fri, 9 Feb 2018 19:31:12 +0000 (19:31 +0000)
committerPeter Edberg <pedberg@unicode.org>
Fri, 9 Feb 2018 19:31:12 +0000 (19:31 +0000)
X-SVN-Rev: 40882

icu4c/source/i18n/islamcal.cpp
icu4c/source/test/intltest/calregts.cpp
icu4c/source/test/intltest/calregts.h
icu4j/main/tests/core/src/com/ibm/icu/dev/test/calendar/CalendarRegressionTest.java

index 4fd0e07d920746d08dd3e2086a52bd4dca818298..b84bedfa0916b170cd2a86514fe740cb8a8a03be 100644 (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);
index f1eb17bbed327e5216893c24d26c796695d4e04f..24951e5b8aa9f829710883b20a63a7d0a1b5bb99 100644 (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 */
index 15d550290935ee61b75070b2b41cdef4261adf81..7d36fab0b4546032a81745a92cb816b8c376899d 100644 (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) ;
index 062ac0bd7a44df16c218191d2442cf87a9d3ee16..4371b6720396717518886d6d9028e159094fa34e 100644 (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