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);
 }
 
 /*

Reply via email to