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