Skip to content

Commit 0c4a35b

Browse files
committed
icaltime: Fails to convert time to time_t before epoch
The time_t of a time before epoch is a negative number, but the code considered a negative number as an incorrectly entered time.
1 parent 7b096e2 commit 0c4a35b

File tree

3 files changed

+40
-11
lines changed

3 files changed

+40
-11
lines changed

ReleaseNotes.txt

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Version 3.0.19 (UNRELEASED):
99
* Improved libicu discrovery on Mac with homebrew
1010
* Properly set DYLD_LIBRARY_PATH on Mac for libical-ical tests
1111
* Resolved known limitation: Negative values are now also supported for `BYMONTHDAY` and `BYYEARDAY`.
12+
* Fix time conversion to time_t for times before epoch
1213

1314
Version 3.0.18 (31 March 2024):
1415
-------------------------------

src/libical/icaltime.c

+18-11
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,11 @@ static int icaltime_leap_days(int y1, int y2)
8080
* in that we don't want the automatic adjustments for
8181
* local daylight savings time applied to the result.
8282
* This function expects well-formed input.
83+
*
84+
* The out_time_t is to store the result, it can be NULL.
85+
* Returns 0 on failure, 1 on success.
8386
*/
84-
static time_t make_time(const struct tm *tm, int tzm)
87+
static int make_time(const struct tm *tm, int tzm, time_t *out_time_t)
8588
{
8689
time_t tim;
8790
int febs;
@@ -91,29 +94,29 @@ static time_t make_time(const struct tm *tm, int tzm)
9194
/* check that month specification within range */
9295

9396
if (tm->tm_mon < 0 || tm->tm_mon > 11)
94-
return ((time_t) - 1);
97+
return 0;
9598

9699
if (tm->tm_year < 2)
97-
return ((time_t)-1);
100+
return 0;
98101

99102
#if (SIZEOF_TIME_T == 4)
100103
/* check that year specification within range */
101104

102105
if (tm->tm_year > 138)
103-
return ((icaltime_t)-1);
106+
return 0;
104107

105108
/* check for upper bound of Jan 17, 2038 (to avoid possibility of 32-bit arithmetic overflow) */
106109
if (tm->tm_year == 138) {
107110
if (tm->tm_mon > 0) {
108-
return ((time_t) - 1);
111+
return 0;
109112
} else if (tm->tm_mday > 17) {
110-
return ((time_t) - 1);
113+
return 0;
111114
}
112115
}
113116
#else
114117
/* We don't support years >= 10000, because the function has not been tested at this range. */
115118
if (tm->tm_year >= 8100) {
116-
return ((time_t)-1);
119+
return 0;
117120
}
118121
#endif /* SIZEOF_TIME_T */
119122

@@ -162,7 +165,10 @@ static time_t make_time(const struct tm *tm, int tzm)
162165

163166
/* return number of seconds since start of the epoch */
164167

165-
return (tim);
168+
if (out_time_t)
169+
*out_time_t = tim;
170+
171+
return 1;
166172
}
167173

168174
/*
@@ -177,7 +183,7 @@ static time_t icaltime_timegm(const struct tm *tm)
177183
time_t seconds;
178184

179185
/* Validate the tm structure by passing it through make_time() */
180-
if (make_time(tm, 0) < 0) {
186+
if (!make_time(tm, 0, NULL)) {
181187
/* we have some invalid data in the tm struct */
182188
return 0;
183189
}
@@ -249,7 +255,7 @@ struct icaltimetype icaltime_today(void)
249255
time_t icaltime_as_timet(const struct icaltimetype tt)
250256
{
251257
struct tm stm;
252-
time_t t;
258+
time_t t = (time_t)-1;
253259

254260
/* If the time is the special null time, return 0. */
255261
if (icaltime_is_null_time(tt)) {
@@ -272,7 +278,8 @@ time_t icaltime_as_timet(const struct icaltimetype tt)
272278
stm.tm_year = tt.year - 1900;
273279
stm.tm_isdst = -1;
274280

275-
t = make_time(&stm, 0);
281+
if (!make_time(&stm, 0, &t))
282+
t = ((time_t)-1);
276283

277284
return t;
278285
}

src/test/regression.c

+21
Original file line numberDiff line numberDiff line change
@@ -2012,6 +2012,27 @@ void do_test_time(const char *zone)
20122012
int_is("icaltime_compare(): same UTC and NY",
20132013
icaltime_compare(icttutc, icttny),
20142014
0);
2015+
2016+
/* Conversion to time_t around the epoch */
2017+
ictt = icaltime_from_string("19691231T235958Z");
2018+
tt = icaltime_as_timet_with_zone(ictt, utczone);
2019+
int_is("convert to time_t EPOCH-2", (int)tt, -2);
2020+
2021+
ictt = icaltime_from_string("19691231T235959Z");
2022+
tt = icaltime_as_timet_with_zone(ictt, utczone);
2023+
int_is("convert to time_t EPOCH-1", (int)tt, -1);
2024+
2025+
ictt = icaltime_from_string("19700101T000000Z");
2026+
tt = icaltime_as_timet_with_zone(ictt, utczone);
2027+
int_is("convert to time_t EPOCH", (int)tt, 0);
2028+
2029+
ictt = icaltime_from_string("19700101T000001Z");
2030+
tt = icaltime_as_timet_with_zone(ictt, utczone);
2031+
int_is("convert to time_t EPOCH+1", (int)tt, 1);
2032+
2033+
ictt = icaltime_from_string("19700101T000002Z");
2034+
tt = icaltime_as_timet_with_zone(ictt, utczone);
2035+
int_is("convert to time_t EPOCH+2", (int)tt, 2);
20152036
}
20162037

20172038
void test_iterators(void)

0 commit comments

Comments
 (0)