Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/lib/libutil PR/42549: Izumi Tsutsui: parsedate does not work...
details: https://anonhg.NetBSD.org/src/rev/bfa7bda4551e
branches: trunk
changeset: 759551:bfa7bda4551e
user: christos <christos%NetBSD.org@localhost>
date: Sun Dec 12 18:39:57 2010 +0000
description:
PR/42549: Izumi Tsutsui: parsedate does not work after 2038.
Fix multiple issues:
- Remove bogus 2038 check and add overflow checks in the appropriate places.
- Correct incomplete leap year calculation that broke things after 2100.
- Check localtime return values
- Change int calculations to time_t to avoid oveflow.
- Consistently check/return -1 and remove bogus comment about not being
able to return -1.
Now:
$ date -d 20991201
Tue Dec 1 00:00:00 EST 2099
$ date -d 40991201
Tue Dec 1 00:00:00 EST 4099
$ date -d 10000000991201
Tue Dec 1 00:00:00 EST 1000000099
TIME=0:04.48 CPU=117.8% (5.288u 0.000s) SWAPS=0 (0+95)pf (0i+0o) (0Kc+0Kd)
$ date -d 100000000991201
date: Cannot parse `100000000991201'
TIME=0:53.48 CPU=99.2% (53.086u 0.000s) SWAPS=0 (0+96)pf (0i+0o) (0Kc+0Kd)
Exit 1
diffstat:
lib/libutil/parsedate.y | 77 +++++++++++++++++++++++++++++++++++-------------
1 files changed, 56 insertions(+), 21 deletions(-)
diffs (162 lines):
diff -r b52d9fac1123 -r bfa7bda4551e lib/libutil/parsedate.y
--- a/lib/libutil/parsedate.y Sun Dec 12 18:33:44 2010 +0000
+++ b/lib/libutil/parsedate.y Sun Dec 12 18:39:57 2010 +0000
@@ -586,6 +586,12 @@
/* NOTREACHED */
}
+static int
+isLeap(int year)
+{
+ return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
+}
+
/* Year is either
* A negative number, which means to use its absolute value (why?)
@@ -607,7 +613,7 @@
31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
time_t tod;
- time_t Julian;
+ time_t Julian, oJulian;
int i;
if (Year < 0)
@@ -616,12 +622,8 @@
Year += 2000;
else if (Year < 100)
Year += 1900;
- DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
- ? 29 : 28;
- /* Checking for 2038 bogusly assumes that time_t is 32 bits. But
- I'm too lazy to try to check for time_t overflow in another way. */
- if (Year < EPOCH || Year > 2038
- || Month < 1 || Month > 12
+ DaysInMonth[1] = isLeap(Year) ? 29 : 28;
+ if (Year < EPOCH || Month < 1 || Month > 12
/* Lint fluff: "conversion from long may lose accuracy" */
|| Day < 1 || Day > DaysInMonth[(int)--Month])
/* FIXME:
@@ -634,16 +636,39 @@
for (Julian = Day - 1, i = 0; i < Month; i++)
Julian += DaysInMonth[i];
- for (i = EPOCH; i < Year; i++)
- Julian += 365 + (i % 4 == 0);
+
+ oJulian = Julian;
+ for (i = EPOCH; i < Year; i++) {
+ Julian += 365 + isLeap(i);
+ if (oJulian > Julian)
+ return -1;
+ oJulian = Julian;
+ }
+
Julian *= SECSPERDAY;
+ if (oJulian > Julian)
+ return -1;
+ oJulian = Julian;
+
Julian += yyTimezone * 60L;
+ if (oJulian > Julian)
+ return -1;
+ oJulian = Julian;
+
if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
return -1;
+
Julian += tod;
- if (DSTmode == DSTon
- || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
- Julian -= 60 * 60;
+ if (oJulian > Julian)
+ return -1;
+
+ if (DSTmode == DSTon || (DSTmode == DSTmaybe)) {
+ struct tm *tm;
+ if ((tm = localtime(&Julian)) == NULL)
+ return -1;
+ if (tm->tm_isdst)
+ Julian -= 60 * 60;
+ }
return Julian;
}
@@ -656,9 +681,16 @@
{
time_t StartDay;
time_t FutureDay;
+ struct tm *tm;
- StartDay = (localtime(&Start)->tm_hour + 1) % 24;
- FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
+ if ((tm = localtime(&Start)) == NULL)
+ return -1;
+ StartDay = (tm->tm_hour + 1) % 24;
+
+ if ((tm = localtime(&Future)) == NULL)
+ return -1;
+ FutureDay = (tm->tm_hour + 1) % 24;
+
return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
}
@@ -694,6 +726,8 @@
if (RelMonth == 0)
return 0;
tm = localtime(&Start);
+ if (tm == NULL)
+ return -1;
Month = 12 * (tm->tm_year + 1900) + tm->tm_mon + RelMonth;
Year = Month / 12;
Month = Month % 12 + 1;
@@ -869,7 +903,7 @@
#define TM_YEAR_ORIGIN 1900
/* Yield A - B, measured in seconds. */
-static long
+static time_t
difftm (struct tm *a, struct tm *b)
{
int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
@@ -884,7 +918,7 @@
/* + difference in years * 365 */
+ (long)(ay-by) * 365
);
- return (60*(60*(24*days + (a->tm_hour - b->tm_hour))
+ return ((time_t)60*(60*(24*days + (a->tm_hour - b->tm_hour))
+ (a->tm_min - b->tm_min))
+ (a->tm_sec - b->tm_sec));
}
@@ -896,7 +930,7 @@
time_t nowt;
int zonet;
time_t Start;
- time_t tod;
+ time_t tod, rm;
yyInput = p;
if (now == NULL || zone == NULL) {
@@ -958,16 +992,17 @@
}
Start += yyRelSeconds;
- Start += RelativeMonth(Start, yyRelMonth);
+ rm = RelativeMonth(Start, yyRelMonth);
+ if (rm == -1)
+ return -1;
+ Start += rm;
if (yyHaveDay && !yyHaveDate) {
tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber);
Start += tod;
}
- /* Have to do *something* with a legitimate -1 so it's distinguishable
- * from the error return value. (Alternately could set errno on error.) */
- return Start == -1 ? 0 : Start;
+ return Start;
}
Home |
Main Index |
Thread Index |
Old Index