Skip to content

Commit

Permalink
ICU-22730 propagate error avoid overflow
Browse files Browse the repository at this point in the history
  • Loading branch information
FrankYFTang committed May 16, 2024
1 parent f017c37 commit 6ac6fdd
Show file tree
Hide file tree
Showing 12 changed files with 83 additions and 41 deletions.
14 changes: 10 additions & 4 deletions icu4c/source/i18n/basictz.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,8 @@ BasicTimeZone::getSimpleRulesNear(UDate date, InitialTimeZoneRule*& initial,

// Get local wall time for the next transition time
Grego::timeToFields(nextTransitionTime + initialRaw + initialDst,
year, month, dom, dow, doy, mid);
year, month, dom, dow, doy, mid, status);
if (U_FAILURE(status)) return;
int32_t weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
// Create DOW rule
DateTimeRule *dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME);
Expand All @@ -192,7 +193,8 @@ BasicTimeZone::getSimpleRulesNear(UDate date, InitialTimeZoneRule*& initial,

// Get local wall time for the next transition time
Grego::timeToFields(tr.getTime() + tr.getFrom()->getRawOffset() + tr.getFrom()->getDSTSavings(),
year, month, dom, dow, doy, mid);
year, month, dom, dow, doy, mid, status);
if (U_FAILURE(status)) return;
weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
// Generate another DOW rule
dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME);
Expand Down Expand Up @@ -223,7 +225,8 @@ BasicTimeZone::getSimpleRulesNear(UDate date, InitialTimeZoneRule*& initial,

// Generate another DOW rule
Grego::timeToFields(tr.getTime() + tr.getFrom()->getRawOffset() + tr.getFrom()->getDSTSavings(),
year, month, dom, dow, doy, mid);
year, month, dom, dow, doy, mid, status);
if (U_FAILURE(status)) return;
weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME);
tr.getTo()->getName(name);
Expand Down Expand Up @@ -484,7 +487,10 @@ BasicTimeZone::getTimeZoneRulesAfter(UDate start, InitialTimeZoneRule*& initial,
} else {
// Calculate the transition year
int32_t year, month, dom, dow, doy, mid;
Grego::timeToFields(tzt.getTime(), year, month, dom, dow, doy, mid);
Grego::timeToFields(tzt.getTime(), year, month, dom, dow, doy, mid, status);
if (U_FAILURE(status)) {
return;
}
// Re-create the rule
ar->getName(name);
LocalPointer<AnnualTimeZoneRule> newAr(new AnnualTimeZoneRule(name, ar->getRawOffset(), ar->getDSTSavings(),
Expand Down
2 changes: 1 addition & 1 deletion icu4c/source/i18n/calendar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1583,7 +1583,7 @@ void Calendar::computeGregorianFields(int32_t julianDay, UErrorCode& ec) {
}
Grego::dayToFields(julianDay, fGregorianYear, fGregorianMonth,
fGregorianDayOfMonth, gregorianDayOfWeekUnused,
fGregorianDayOfYear);
fGregorianDayOfYear, ec);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion icu4c/source/i18n/chnsecal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ int64_t ChineseCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, U
int32_t unusedDayOfWeek;
int32_t unusedDayOfMonth;
int32_t unusedDayOfYear;
Grego::dayToFields(newMoon, gyear, unusedMonth, unusedDayOfWeek, unusedDayOfMonth, unusedDayOfYear);
Grego::dayToFields(newMoon, gyear, unusedMonth, unusedDayOfWeek, unusedDayOfMonth, unusedDayOfYear, status);

struct MonthInfo monthInfo = computeMonthInfo(setting, gyear, newMoon, status);
if (U_FAILURE(status)) {
Expand Down
3 changes: 2 additions & 1 deletion icu4c/source/i18n/erarules.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,8 @@ void EraRules::initCurrentEra() {
}

int year, month0, dom, dow, doy, mid;
Grego::timeToFields(localMillis, year, month0, dom, dow, doy, mid);
Grego::timeToFields(localMillis, year, month0, dom, dow, doy, mid, ec);
if (U_FAILURE(ec)) return;
int currentEncodedDate = encodeDate(year, month0 + 1 /* changes to 1-base */, dom);
int eraIdx = numEras - 1;
while (eraIdx > 0) {
Expand Down
13 changes: 9 additions & 4 deletions icu4c/source/i18n/gregoimp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,14 @@ int64_t Grego::fieldsToDay(int32_t year, int32_t month, int32_t dom) {
}

void Grego::dayToFields(int32_t day, int32_t& year, int32_t& month,
int32_t& dom, int32_t& dow, int32_t& doy) {
int32_t& dom, int32_t& dow, int32_t& doy, UErrorCode& status) {

if (U_FAILURE(status)) return;
// Convert from 1970 CE epoch to 1 CE epoch (Gregorian calendar)
day += JULIAN_1970_CE - JULIAN_1_CE;
if (uprv_add32_overflow(day, JULIAN_1970_CE - JULIAN_1_CE, &day)) {
status = U_ILLEGAL_ARGUMENT_ERROR;
return;
}

// Convert from the day number to the multiple radix
// representation. We use 400-year, 100-year, and 4-year cycles.
Expand Down Expand Up @@ -156,11 +160,12 @@ void Grego::dayToFields(int32_t day, int32_t& year, int32_t& month,
}

void Grego::timeToFields(UDate time, int32_t& year, int32_t& month,
int32_t& dom, int32_t& dow, int32_t& doy, int32_t& mid) {
int32_t& dom, int32_t& dow, int32_t& doy, int32_t& mid, UErrorCode& status) {
if (U_FAILURE(status)) return;
double millisInDay;
double day = ClockMath::floorDivide((double)time, (double)U_MILLIS_PER_DAY, &millisInDay);
mid = (int32_t)millisInDay;
dayToFields(day, year, month, dom, dow, doy);
dayToFields(day, year, month, dom, dow, doy, status);
}

int32_t Grego::dayOfWeek(int32_t day) {
Expand Down
13 changes: 8 additions & 5 deletions icu4c/source/i18n/gregoimp.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,9 +208,10 @@ class Grego {
* @param dom output parameter to receive day-of-month (1-based)
* @param dow output parameter to receive day-of-week (1-based, 1==Sun)
* @param doy output parameter to receive day-of-year (1-based)
* @param status error code.
*/
static void dayToFields(int32_t day, int32_t& year, int32_t& month,
int32_t& dom, int32_t& dow, int32_t& doy);
int32_t& dom, int32_t& dow, int32_t& doy, UErrorCode& status);

/**
* Convert a 1970-epoch day number to proleptic Gregorian year,
Expand All @@ -220,9 +221,10 @@ class Grego {
* @param month output parameter to receive month (0-based, 0==Jan)
* @param dom output parameter to receive day-of-month (1-based)
* @param dow output parameter to receive day-of-week (1-based, 1==Sun)
* @param status error code.
*/
static inline void dayToFields(int32_t day, int32_t& year, int32_t& month,
int32_t& dom, int32_t& dow);
int32_t& dom, int32_t& dow, UErrorCode& status);

/**
* Convert a 1970-epoch milliseconds to proleptic Gregorian year,
Expand All @@ -234,9 +236,10 @@ class Grego {
* @param dow output parameter to receive day-of-week (1-based, 1==Sun)
* @param doy output parameter to receive day-of-year (1-based)
* @param mid output parameter to receive millis-in-day
* @param status error code.
*/
static void timeToFields(UDate time, int32_t& year, int32_t& month,
int32_t& dom, int32_t& dow, int32_t& doy, int32_t& mid);
int32_t& dom, int32_t& dow, int32_t& doy, int32_t& mid, UErrorCode& status);

/**
* Return the day of week on the 1970-epoch day
Expand Down Expand Up @@ -303,9 +306,9 @@ Grego::previousMonthLength(int y, int m) {
}

inline void Grego::dayToFields(int32_t day, int32_t& year, int32_t& month,
int32_t& dom, int32_t& dow) {
int32_t& dom, int32_t& dow, UErrorCode& status) {
int32_t doy_unused;
dayToFields(day,year,month,dom,dow,doy_unused);
dayToFields(day,year,month,dom,dow,doy_unused, status);
}

inline double Grego::julianDayToMillis(int32_t julian)
Expand Down
9 changes: 5 additions & 4 deletions icu4c/source/i18n/indiancal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,10 @@ static double gregorianToJD(int32_t year, int32_t month, int32_t date) {
* Month is 0 based.
* @param jd The Julian Day
*/
static int32_t* jdToGregorian(double jd, int32_t gregorianDate[3]) {
static int32_t* jdToGregorian(double jd, int32_t gregorianDate[3], UErrorCode& status) {
int32_t gdow;
Grego::dayToFields(jd - kEpochStartAsJulianDay,
gregorianDate[0], gregorianDate[1], gregorianDate[2], gdow);
gregorianDate[0], gregorianDate[1], gregorianDate[2], gdow, status);
return gregorianDate;
}

Expand Down Expand Up @@ -263,13 +263,14 @@ int32_t IndianCalendar::handleGetExtendedYear(UErrorCode& status) {
* method is called. The getGregorianXxx() methods return Gregorian
* calendar equivalents for the given Julian day.
*/
void IndianCalendar::handleComputeFields(int32_t julianDay, UErrorCode& /* status */) {
void IndianCalendar::handleComputeFields(int32_t julianDay, UErrorCode& status) {
double jdAtStartOfGregYear;
int32_t leapMonth, IndianYear, yday, IndianMonth, IndianDayOfMonth, mday;
int32_t gregorianYear; // Stores gregorian date corresponding to Julian day;
int32_t gd[3];

gregorianYear = jdToGregorian(julianDay, gd)[0]; // Gregorian date for Julian day
gregorianYear = jdToGregorian(julianDay, gd, status)[0]; // Gregorian date for Julian day
if (U_FAILURE(status)) return;
IndianYear = gregorianYear - INDIAN_ERA_START; // Year in Saka era
jdAtStartOfGregYear = gregorianToJD(gregorianYear, 0, 1); // JD at start of Gregorian year
yday = (int32_t)(julianDay - jdAtStartOfGregYear); // Day number in Gregorian year (starting from 0)
Expand Down
5 changes: 4 additions & 1 deletion icu4c/source/i18n/olsontz.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,10 @@ UBool OlsonTimeZone::useDaylightTime() const {
}

int32_t year, month, dom, dow, doy, mid;
Grego::timeToFields(current, year, month, dom, dow, doy, mid);
UErrorCode status = U_ZERO_ERROR;
Grego::timeToFields(current, year, month, dom, dow, doy, mid, status);
U_ASSERT(U_SUCCESS(status));
if (U_FAILURE(status)) return false; // If error, just return false.

// Find start of this year, and start of next year
double start = Grego::fieldsToDay(year, 0, 1) * SECONDS_PER_DAY;
Expand Down
6 changes: 4 additions & 2 deletions icu4c/source/i18n/simpletz.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,8 @@ SimpleTimeZone::getOffsetFromLocal(UDate date, UTimeZoneLocalOption nonExistingT
}
int32_t day = dday;

Grego::dayToFields(day, year, month, dom, dow);
Grego::dayToFields(day, year, month, dom, dow, status);
if (U_FAILURE(status)) return;

savingsDST = getOffset(GregorianCalendar::AD, year, month, dom,
(uint8_t) dow, millis,
Expand Down Expand Up @@ -554,7 +555,8 @@ SimpleTimeZone::getOffsetFromLocal(UDate date, UTimeZoneLocalOption nonExistingT
}
if (recalc) {
day = ClockMath::floorDivide(date, U_MILLIS_PER_DAY, &millis);
Grego::dayToFields(day, year, month, dom, dow);
Grego::dayToFields(day, year, month, dom, dow, status);
if (U_FAILURE(status)) return;
savingsDST = getOffset(GregorianCalendar::AD, year, month, dom,
(uint8_t) dow, millis,
Grego::monthLength(year, month),
Expand Down
3 changes: 2 additions & 1 deletion icu4c/source/i18n/timezone.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -738,7 +738,8 @@ void TimeZone::getOffset(UDate date, UBool local, int32_t& rawOffset,
ec = U_ILLEGAL_ARGUMENT_ERROR;
return;
}
Grego::dayToFields(day, year, month, dom, dow);
Grego::dayToFields(day, year, month, dom, dow, ec);
if (U_FAILURE(ec)) return;

dstOffset = getOffset(GregorianCalendar::AD, year, month, dom,
(uint8_t) dow, millis,
Expand Down
8 changes: 6 additions & 2 deletions icu4c/source/i18n/tzrule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,9 @@ AnnualTimeZoneRule::getNextStart(UDate base,
UBool inclusive,
UDate& result) const {
int32_t year, month, dom, dow, doy, mid;
Grego::timeToFields(base, year, month, dom, dow, doy, mid);
UErrorCode status = U_ZERO_ERROR;
Grego::timeToFields(base, year, month, dom, dow, doy, mid, status);
U_ASSERT(U_SUCCESS(status));
if (year < fStartYear) {
return getFirstStart(prevRawOffset, prevDSTSavings, result);
}
Expand All @@ -380,7 +382,9 @@ AnnualTimeZoneRule::getPreviousStart(UDate base,
UBool inclusive,
UDate& result) const {
int32_t year, month, dom, dow, doy, mid;
Grego::timeToFields(base, year, month, dom, dow, doy, mid);
UErrorCode status = U_ZERO_ERROR;
Grego::timeToFields(base, year, month, dom, dow, doy, mid, status);
U_ASSERT(U_SUCCESS(status));
if (year > fEndYear) {
return getFinalStart(prevRawOffset, prevDSTSavings, result);
}
Expand Down
46 changes: 31 additions & 15 deletions icu4c/source/i18n/vtzone.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,11 @@ static UnicodeString& appendMillis(UDate date, UnicodeString& str) {
/*
* Convert date/time to RFC2445 Date-Time form #1 DATE WITH LOCAL TIME
*/
static UnicodeString& getDateTimeString(UDate time, UnicodeString& str) {
static UnicodeString& getDateTimeString(UDate time, UnicodeString& str, UErrorCode& status) {
if (U_FAILURE(status)) {return str;}
int32_t year, month, dom, dow, doy, mid;
Grego::timeToFields(time, year, month, dom, dow, doy, mid);
Grego::timeToFields(time, year, month, dom, dow, doy, mid, status);
if (U_FAILURE(status)) {return str;}

str.remove();
appendAsciiDigits(year, 4, str);
Expand All @@ -206,8 +208,8 @@ static UnicodeString& getDateTimeString(UDate time, UnicodeString& str) {
/*
* Convert date/time to RFC2445 Date-Time form #2 DATE WITH UTC TIME
*/
static UnicodeString& getUTCDateTimeString(UDate time, UnicodeString& str) {
getDateTimeString(time, str);
static UnicodeString& getUTCDateTimeString(UDate time, UnicodeString& str, UErrorCode& status) {
getDateTimeString(time, str, status);
str.append((char16_t)0x005A /*'Z'*/);
return str;
}
Expand Down Expand Up @@ -675,7 +677,10 @@ static TimeZoneRule* createRuleByRRULE(const UnicodeString& zonename, int rawOff
// Calculate start/end year and missing fields
int32_t startYear, startMonth, startDOM, startDOW, startDOY, startMID;
Grego::timeToFields(start + fromOffset, startYear, startMonth, startDOM,
startDOW, startDOY, startMID);
startDOW, startDOY, startMID, status);
if (U_FAILURE(status)) {
return nullptr;
}
if (month == -1) {
// If BYMONTH is not set, use the month of DTSTART
month = startMonth;
Expand All @@ -688,7 +693,8 @@ static TimeZoneRule* createRuleByRRULE(const UnicodeString& zonename, int rawOff
int32_t endYear;
if (until != MIN_MILLIS) {
int32_t endMonth, endDOM, endDOW, endDOY, endMID;
Grego::timeToFields(until, endYear, endMonth, endDOM, endDOW, endDOY, endMID);
Grego::timeToFields(until, endYear, endMonth, endDOM, endDOW, endDOY, endMID, status);
if (U_FAILURE(status)) return nullptr;
} else {
endYear = AnnualTimeZoneRule::MAX_YEAR;
}
Expand Down Expand Up @@ -1669,7 +1675,8 @@ VTimeZone::parse(UErrorCode& status) {
} else {
// Update the end year
int32_t y, m, d, dow, doy, mid;
Grego::timeToFields(start, y, m, d, dow, doy, mid);
Grego::timeToFields(start, y, m, d, dow, doy, mid, status);
if (U_FAILURE(status)) return;
newRule.adoptInsteadAndCheckErrorCode(
new AnnualTimeZoneRule(
finalRule->getName(tznam),
Expand Down Expand Up @@ -1709,6 +1716,7 @@ VTimeZone::parse(UErrorCode& status) {

void
VTimeZone::write(VTZWriter& writer, UErrorCode& status) const {
if (U_FAILURE(status)) return;
if (vtzlines != nullptr) {
for (int32_t i = 0; i < vtzlines->size(); i++) {
UnicodeString *line = (UnicodeString*)vtzlines->elementAt(i);
Expand All @@ -1723,7 +1731,8 @@ VTimeZone::write(VTZWriter& writer, UErrorCode& status) const {
UnicodeString utcString;
writer.write(ICAL_LASTMOD);
writer.write(COLON);
writer.write(getUTCDateTimeString(lastmod, utcString));
writer.write(getUTCDateTimeString(lastmod, utcString, status));
if (U_FAILURE(status)) return;
writer.write(ICAL_NEWLINE);
} else {
writer.write(*line);
Expand Down Expand Up @@ -1913,7 +1922,8 @@ VTimeZone::writeZone(VTZWriter& w, BasicTimeZone& basictz,
int32_t fromOffset = tzt.getFrom()->getRawOffset() + tzt.getFrom()->getDSTSavings();
int32_t fromDSTSavings = tzt.getFrom()->getDSTSavings();
int32_t toOffset = tzt.getTo()->getRawOffset() + tzt.getTo()->getDSTSavings();
Grego::timeToFields(tzt.getTime() + fromOffset, year, month, dom, dow, doy, mid);
Grego::timeToFields(tzt.getTime() + fromOffset, year, month, dom, dow, doy, mid, status);
if (U_FAILURE(status)) return;
int32_t weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
UBool sameRule = false;
const AnnualTimeZoneRule *atzrule;
Expand Down Expand Up @@ -2158,7 +2168,7 @@ VTimeZone::writeHeaders(VTZWriter& writer, UErrorCode& status) const {
UnicodeString lastmodStr;
writer.write(ICAL_LASTMOD);
writer.write(COLON);
writer.write(getUTCDateTimeString(lastmod, lastmodStr));
writer.write(getUTCDateTimeString(lastmod, lastmodStr, status));
writer.write(ICAL_NEWLINE);
}
}
Expand Down Expand Up @@ -2195,8 +2205,11 @@ VTimeZone::writeZonePropsByTime(VTZWriter& writer, UBool isDst, const UnicodeStr
writer.write(ICAL_RDATE);
writer.write(COLON);
UnicodeString timestr;
writer.write(getDateTimeString(time + fromOffset, timestr));
writer.write(getDateTimeString(time + fromOffset, timestr, status));
writer.write(ICAL_NEWLINE);
if (U_FAILURE(status)) {
return;
}
}
endZoneProps(writer, isDst, status);
if (U_FAILURE(status)) {
Expand Down Expand Up @@ -2229,7 +2242,7 @@ VTimeZone::writeZonePropsByDOM(VTZWriter& writer, UBool isDst, const UnicodeStri
appendAsciiDigits(dayOfMonth, 0, dstr);
writer.write(dstr);
if (untilTime != MAX_MILLIS) {
appendUNTIL(writer, getDateTimeString(untilTime + fromOffset, dstr), status);
appendUNTIL(writer, getDateTimeString(untilTime + fromOffset, dstr, status), status);
if (U_FAILURE(status)) {
return;
}
Expand Down Expand Up @@ -2265,7 +2278,7 @@ VTimeZone::writeZonePropsByDOW(VTZWriter& writer, UBool isDst, const UnicodeStri
writer.write(ICAL_DOW_NAMES[dayOfWeek - 1]); // SU, MO, TU...

if (untilTime != MAX_MILLIS) {
appendUNTIL(writer, getDateTimeString(untilTime + fromOffset, dstr), status);
appendUNTIL(writer, getDateTimeString(untilTime + fromOffset, dstr, status), status);
if (U_FAILURE(status)) {
return;
}
Expand Down Expand Up @@ -2390,7 +2403,7 @@ VTimeZone::writeZonePropsByDOW_GEQ_DOM_sub(VTZWriter& writer, int32_t month, int
}

if (untilTime != MAX_MILLIS) {
appendUNTIL(writer, getDateTimeString(untilTime + fromOffset, dstr), status);
appendUNTIL(writer, getDateTimeString(untilTime + fromOffset, dstr, status), status);
if (U_FAILURE(status)) {
return;
}
Expand Down Expand Up @@ -2529,7 +2542,10 @@ VTimeZone::beginZoneProps(VTZWriter& writer, UBool isDst, const UnicodeString& z
// DTSTART
writer.write(ICAL_DTSTART);
writer.write(COLON);
writer.write(getDateTimeString(startTime + fromOffset, dstr));
writer.write(getDateTimeString(startTime + fromOffset, dstr, status));
if (U_FAILURE(status)) {
return;
}
writer.write(ICAL_NEWLINE);
}

Expand Down

0 comments on commit 6ac6fdd

Please sign in to comment.