Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/lib/libc/time According to TOG:



details:   https://anonhg.NetBSD.org/src/rev/5ed771c69791
branches:  trunk
changeset: 751378:5ed771c69791
user:      christos <christos%NetBSD.org@localhost>
date:      Tue Feb 02 19:04:37 2010 +0000

description:
According to TOG:
- asctime{,_r}, ctime{,_r} may return NULL; document that, and avoid coredumps.
- gmtime{,_r}, localtime{,_r} may return NULL and set EOVERFLOW, document and
  set errno.
- when mktime returns (time_t)-1, make it set EOVERFLOW and document it.

XXX: Should be pulled up to 5.x

diffstat:

 lib/libc/time/ctime.3     |  61 ++++++++++++++++++++++++++++++++++++++++++++--
 lib/libc/time/localtime.c |  56 +++++++++++++++++++++++++++++++-----------
 2 files changed, 99 insertions(+), 18 deletions(-)

diffs (226 lines):

diff -r 6f01fe6888b6 -r 5ed771c69791 lib/libc/time/ctime.3
--- a/lib/libc/time/ctime.3     Tue Feb 02 19:03:31 2010 +0000
+++ b/lib/libc/time/ctime.3     Tue Feb 02 19:04:37 2010 +0000
@@ -1,5 +1,5 @@
-.\"    $NetBSD: ctime.3,v 1.29 2010/01/08 17:16:56 joerg Exp $
-.Dd March 31, 2001
+.\"    $NetBSD: ctime.3,v 1.30 2010/02/02 19:04:37 christos Exp $
+.Dd February 2, 2010
 .Dt CTIME 3
 .Os
 .Sh NAME
@@ -154,7 +154,8 @@
 are determined.
 .Fn mktime
 returns the specified calendar time; if the calendar time cannot be
-represented, it returns -1.
+represented, it returns 
+.Va "(time_t)-1" .
 .Pp
 .Fn difftime
 returns the difference between two calendar times,
@@ -195,6 +196,60 @@
 is the offset (in seconds) of the time represented
 from UTC, with positive values indicating east
 of the Prime Meridian.
+.Sh RETURN VALUES
+On success the
+.Nm asctime 
+and
+.Nm ctime
+functions return a pointer to a static character buffer, and the
+.Nm asctime_r 
+and
+.Nm ctime_r
+function return a pointer to the user-supplied buffer.
+On failure they all return
+.Dv NULL
+and no errors are defined for them.
+On success the
+.Nm gmtime ,
+and
+.Nm localtime
+functions return a pointer to a statically allocated
+.Va "struct tm"
+whereas the
+.Nm gmtime_r 
+and
+.Nm localtime_r
+functions return a pointer to the user-supplied
+.Va "struct tm" .
+On failure they all return
+.Dv NULL
+and the global variable
+.Va errno
+is set to indicate the error.
+The
+.Nm mktime
+function returns the specified time since the Epoch as a
+.Va time_t
+type value. If the time cannot be represented, then
+.Nm mktime
+returns
+.Va "(time_t)-1"
+setting the global variable
+.Va errno
+to indicate the error.
+.Sh ERRORS
+The
+.Nm gmtime_r ,
+.Nm localtime_r ,
+.Nm gmtime ,
+.Nm localtime ,
+and
+.Nm mktime
+will fail when:
+.Bl -tag -width Er
+.It Bq Er EOVERFLOW
+The result cannot be represented.
+.El
 .Sh FILES
 .Bl -tag -width /usr/share/zoneinfo/posixrules -compact
 .It Pa /etc/localtime
diff -r 6f01fe6888b6 -r 5ed771c69791 lib/libc/time/localtime.c
--- a/lib/libc/time/localtime.c Tue Feb 02 19:03:31 2010 +0000
+++ b/lib/libc/time/localtime.c Tue Feb 02 19:04:37 2010 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: localtime.c,v 1.45 2009/12/31 22:49:16 mlelstv Exp $   */
+/*     $NetBSD: localtime.c,v 1.46 2010/02/02 19:04:37 christos Exp $  */
 
 /*
 ** This file is in the public domain, so clarified as of
@@ -10,7 +10,7 @@
 #if 0
 static char    elsieid[] = "@(#)localtime.c    8.9";
 #else
-__RCSID("$NetBSD: localtime.c,v 1.45 2009/12/31 22:49:16 mlelstv Exp $");
+__RCSID("$NetBSD: localtime.c,v 1.46 2010/02/02 19:04:37 christos Exp $");
 #endif
 #endif /* LIBC_SCCS and not lint */
 
@@ -708,17 +708,23 @@
        register char   c;
        register int    num;
 
-       if (strp == NULL || !is_digit(c = *strp))
+       if (strp == NULL || !is_digit(c = *strp)) {
+               errno = EINVAL;
                return NULL;
+       }
        num = 0;
        do {
                num = num * 10 + (c - '0');
-               if (num > max)
+               if (num > max) {
+                       errno = EOVERFLOW;
                        return NULL;    /* illegal value */
+               }
                c = *++strp;
        } while (is_digit(c));
-       if (num < min)
+       if (num < min) {
+               errno = EINVAL;
                return NULL;            /* illegal value */
+       }
        *nump = num;
        return strp;
 }
@@ -1343,8 +1349,10 @@
                                newt += seconds;
                        else    newt -= seconds;
                        if (newt < sp->ats[0] ||
-                               newt > sp->ats[sp->timecnt - 1])
+                               newt > sp->ats[sp->timecnt - 1]) {
+                                       errno = EOVERFLOW;
                                        return NULL;    /* "cannot happen" */
+                       }
                        result = localsub(&newt, offset, tmp);
                        if (result == tmp) {
                                register time_t newy;
@@ -1354,8 +1362,10 @@
                                        newy -= (time_t)icycles * YEARSPERREPEAT;
                                else    newy += (time_t)icycles * YEARSPERREPEAT;
                                tmp->tm_year = (int)newy;
-                               if (tmp->tm_year != newy)
+                               if (tmp->tm_year != newy) {
+                                       errno = EOVERFLOW;
                                        return NULL;
+                               }
                        }
                        return result;
        }
@@ -1579,13 +1589,17 @@
 
                tdelta = tdays / DAYSPERLYEAR;
                idelta = (int) tdelta;
-               if (tdelta - idelta >= 1 || idelta - tdelta >= 1)
+               if (tdelta - idelta >= 1 || idelta - tdelta >= 1) {
+                       errno = EOVERFLOW;
                        return NULL;
+               }
                if (idelta == 0)
                        idelta = (tdays < 0) ? -1 : 1;
                newy = y;
-               if (increment_overflow(&newy, idelta))
+               if (increment_overflow(&newy, idelta)) {
+                       errno = EOVERFLOW;
                        return NULL;
+               }
                leapdays = leaps_thru_end_of(newy - 1) -
                        leaps_thru_end_of(y - 1);
                tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
@@ -1613,18 +1627,24 @@
                ++idays;
        }
        while (idays < 0) {
-               if (increment_overflow(&y, -1))
+               if (increment_overflow(&y, -1)) {
+                       errno = EOVERFLOW;
                        return NULL;
+               }
                idays += year_lengths[isleap(y)];
        }
        while (idays >= year_lengths[isleap(y)]) {
                idays -= year_lengths[isleap(y)];
-               if (increment_overflow(&y, 1))
+               if (increment_overflow(&y, 1)) {
+                       errno = EOVERFLOW;
                        return NULL;
+               }
        }
        tmp->tm_year = y;
-       if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
+       if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE)) {
+               errno = EOVERFLOW;
                return NULL;
+       }
        tmp->tm_yday = idays;
        /*
        ** The "extra" mods below avoid overflow problems.
@@ -1667,7 +1687,10 @@
 **     to local time in the form of a string. It is equivalent to
 **             asctime(localtime(timer))
 */
-       return asctime(localtime(timep));
+       struct tm *rtm = localtime(timep);
+       if (rtm == NULL)
+               return NULL;
+       return asctime(rtm);
 }
 
 char *
@@ -1675,9 +1698,12 @@
 const time_t * const   timep;
 char *                 buf;
 {
-       struct tm       mytm;
+       struct tm       mytm, *rtm;
 
-       return asctime_r(localtime_r(timep, &mytm), buf);
+       rtm = localtime_r(timep, &mytm);
+       if (rtm == NULL)
+               return NULL;
+       return asctime_r(rtm, buf);
 }
 
 /*



Home | Main Index | Thread Index | Old Index