Module Name: src Committed By: christos Date: Tue Feb 2 19:04:38 UTC 2010
Modified Files: src/lib/libc/time: ctime.3 localtime.c Log Message: 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 To generate a diff of this commit: cvs rdiff -u -r1.29 -r1.30 src/lib/libc/time/ctime.3 cvs rdiff -u -r1.45 -r1.46 src/lib/libc/time/localtime.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/lib/libc/time/ctime.3 diff -u src/lib/libc/time/ctime.3:1.29 src/lib/libc/time/ctime.3:1.30 --- src/lib/libc/time/ctime.3:1.29 Fri Jan 8 12:16:56 2010 +++ src/lib/libc/time/ctime.3 Tue Feb 2 14:04:37 2010 @@ -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 Index: src/lib/libc/time/localtime.c diff -u src/lib/libc/time/localtime.c:1.45 src/lib/libc/time/localtime.c:1.46 --- src/lib/libc/time/localtime.c:1.45 Thu Dec 31 17:49:16 2009 +++ src/lib/libc/time/localtime.c Tue Feb 2 14:04:37 2010 @@ -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); } /*