From nobody@FreeBSD.org  Sat Apr  3 06:03:55 2010
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id 941A2106564A
	for <freebsd-gnats-submit@FreeBSD.org>; Sat,  3 Apr 2010 06:03:55 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (www.freebsd.org [IPv6:2001:4f8:fff6::21])
	by mx1.freebsd.org (Postfix) with ESMTP id 832E68FC08
	for <freebsd-gnats-submit@FreeBSD.org>; Sat,  3 Apr 2010 06:03:55 +0000 (UTC)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.14.3/8.14.3) with ESMTP id o3363tMg040536
	for <freebsd-gnats-submit@FreeBSD.org>; Sat, 3 Apr 2010 06:03:55 GMT
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.14.3/8.14.3/Submit) id o3363tYR040535;
	Sat, 3 Apr 2010 06:03:55 GMT
	(envelope-from nobody)
Message-Id: <201004030603.o3363tYR040535@www.freebsd.org>
Date: Sat, 3 Apr 2010 06:03:55 GMT
From: NARUSE, Yui <naruse@airemix.jp>
To: freebsd-gnats-submit@FreeBSD.org
Subject: localtime doesn't handle overflow
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         145341
>Category:       kern
>Synopsis:       localtime(3) doesn't handle overflow
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    edwin
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sat Apr 03 07:47:08 UTC 2010
>Closed-Date:    
>Last-Modified:  Sat Apr 03 17:59:43 UTC 2010
>Originator:     NARUSE, Yui
>Release:        FreeBSD 8.0-STABLE amd64
>Organization:
>Environment:
FreeBSD windy.airemix.net 8.0-STABLE FreeBSD 8.0-STABLE #9: Fri Feb 26 20:47:20 JST 2010     root@windy.airemix.net:/usr/obj/usr/src/sys/GENERIC  amd64

>Description:
gmtime, gmtime_r, localtime and localtime_r may overflow
when the value of year is beyond signed int: year 2147481747 problem.

POSIX says, on such overflow gmtime() shall return NULL
and set errnor as EOVERFLOW, but FreeBSD 8 doesn't.
http://www.opengroup.org/onlinepubs/9699919799/functions/gmtime.html

>How-To-Repeat:
Run following code:

----------
#include <stdio.h>
#include <time.h>
#include <errno.h>

void t_inspect(time_t t)
{
    struct tm *tp;
    errno = 0;
    tp = gmtime(&t);
    printf("t:%ld, tp: %p errno:%d\n",t,tp,errno);
    if (tp)
        printf("sec: %d, min:%d, hour:%d, mday:%d, mon:%d, year:%d,\n" \
                "wday:%d, yday:%d, isdst:%d, gmtoff: %ld, zone: %s\n",
                tp->tm_sec, tp->tm_min, tp->tm_hour, tp->tm_mday,
                tp->tm_mon, tp->tm_year, tp->tm_wday, tp->tm_yday,
                tp->tm_isdst, tp->tm_gmtoff, tp->tm_zone);
}

int main(void)
{
    time_t t = 67767976233532799;
    t_inspect(t-1);
    t_inspect(t);
    t_inspect(t+1);
    return 0;
}
----------

and got following result; second and third output equal.

----------
t:67767976233532798, tp: 0x80099c900 errno:2
sec: 58, min:59, hour:23, mday:31, mon:11, year:2147481747,
wday:2, yday:364, isdst:0, gmtoff: 0, zone: UTC
t:67767976233532799, tp: 0x80099c900 errno:0
sec: 59, min:59, hour:23, mday:31, mon:11, year:2147481747,
wday:2, yday:364, isdst:0, gmtoff: 0, zone: UTC
t:67767976233532800, tp: 0x80099c900 errno:0
sec: 59, min:59, hour:23, mday:31, mon:11, year:2147481747,
wday:2, yday:364, isdst:0, gmtoff: 0, zone: UTC
>Fix:


>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->edwin 
Responsible-Changed-By: edwin 
Responsible-Changed-When: Sat Apr 3 10:36:21 UTC 2010 
Responsible-Changed-Why:  
I'll grab it. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=145341 

From: Garrett Cooper <yanefbsd@gmail.com>
To: NARUSE@freebsd.org, Yui <naruse@airemix.jp>
Cc: freebsd-gnats-submit@freebsd.org, Edwin Groothuis <edwin@freebsd.org>
Subject: Re: misc/145341: localtime doesn't handle overflow
Date: Sat, 3 Apr 2010 02:30:30 -0700

 On Fri, Apr 2, 2010 at 11:03 PM,  <NARUSE@freebsd.org> wrote:
 >
 >>Number: =A0 =A0 =A0 =A0 145341
 >>Category: =A0 =A0 =A0 misc
 >>Synopsis: =A0 =A0 =A0 localtime doesn't handle overflow
 >>Confidential: =A0 no
 >>Severity: =A0 =A0 =A0 non-critical
 >>Priority: =A0 =A0 =A0 low
 >>Responsible: =A0 =A0freebsd-bugs
 >>State: =A0 =A0 =A0 =A0 =A0open
 >>Quarter:
 >>Keywords:
 >>Date-Required:
 >>Class: =A0 =A0 =A0 =A0 =A0sw-bug
 >>Submitter-Id: =A0 current-users
 >>Arrival-Date: =A0 Sat Apr 03 07:47:08 UTC 2010
 >>Closed-Date:
 >>Last-Modified:
 >>Originator: =A0 =A0 NARUSE, Yui
 >>Release: =A0 =A0 =A0 =A0FreeBSD 8.0-STABLE amd64
 >>Organization:
 >>Environment:
 > FreeBSD windy.airemix.net 8.0-STABLE FreeBSD 8.0-STABLE #9: Fri Feb 26 20=
 :47:20 JST 2010 =A0 =A0 root@windy.airemix.net:/usr/obj/usr/src/sys/GENERIC=
  =A0amd64
 >
 >>Description:
 > gmtime, gmtime_r, localtime and localtime_r may overflow
 > when the value of year is beyond signed int: year 2147481747 problem.
 >
 > POSIX says, on such overflow gmtime() shall return NULL
 > and set errnor as EOVERFLOW, but FreeBSD 8 doesn't.
 > http://www.opengroup.org/onlinepubs/9699919799/functions/gmtime.html
 >
 >>How-To-Repeat:
 > Run following code:
 >
 > ----------
 > #include <stdio.h>
 > #include <time.h>
 > #include <errno.h>
 >
 > void t_inspect(time_t t)
 > {
 > =A0 =A0struct tm *tp;
 > =A0 =A0errno =3D 0;
 > =A0 =A0tp =3D gmtime(&t);
 > =A0 =A0printf("t:%ld, tp: %p errno:%d\n",t,tp,errno);
 > =A0 =A0if (tp)
 > =A0 =A0 =A0 =A0printf("sec: %d, min:%d, hour:%d, mday:%d, mon:%d, year:%d=
 ,\n" \
 > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"wday:%d, yday:%d, isdst:%d, gmtoff: %ld, =
 zone: %s\n",
 > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0tp->tm_sec, tp->tm_min, tp->tm_hour, tp->t=
 m_mday,
 > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0tp->tm_mon, tp->tm_year, tp->tm_wday, tp->=
 tm_yday,
 > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0tp->tm_isdst, tp->tm_gmtoff, tp->tm_zone);
 > }
 >
 > int main(void)
 > {
 > =A0 =A0time_t t =3D 67767976233532799;
 > =A0 =A0t_inspect(t-1);
 > =A0 =A0t_inspect(t);
 > =A0 =A0t_inspect(t+1);
 > =A0 =A0return 0;
 > }
 > ----------
 >
 > and got following result; second and third output equal.
 >
 > ----------
 > t:67767976233532798, tp: 0x80099c900 errno:2
 > sec: 58, min:59, hour:23, mday:31, mon:11, year:2147481747,
 > wday:2, yday:364, isdst:0, gmtoff: 0, zone: UTC
 > t:67767976233532799, tp: 0x80099c900 errno:0
 > sec: 59, min:59, hour:23, mday:31, mon:11, year:2147481747,
 > wday:2, yday:364, isdst:0, gmtoff: 0, zone: UTC
 > t:67767976233532800, tp: 0x80099c900 errno:0
 > sec: 59, min:59, hour:23, mday:31, mon:11, year:2147481747,
 > wday:2, yday:364, isdst:0, gmtoff: 0, zone: UTC
 
     CCing Edwin as he's been doing a lot of work on this lately. This
 item is still an issue on CURRENT as of r205310 (in fact it might be
 worse because it's not reporting any errnos of any flavor whereas the
 first iteration was reporting EINVAL on 8.0-RELEASE -- Edwin can
 confirm whether or not this is the case though):
 
 $ ./test_gmtime_overflow
 t: 2147483646, tp: 0x800877c80 errno: 0
 sec: 6, min: 14, hour: 3, mday: 19, mon: 0, year: 138, wday: 2, yday:
 18, isdst: 0, gmtoff: 0, zone: UTC
 t: 2147483647, tp: 0x800877c80 errno: 0
 sec: 7, min: 14, hour: 3, mday: 19, mon: 0, year: 138, wday: 2, yday:
 18, isdst: 0, gmtoff: 0, zone: UTC
 t: 2147483648, tp: 0x800877c80 errno: 0
 sec: 8, min: 14, hour: 3, mday: 19, mon: 0, year: 138, wday: 2, yday:
 18, isdst: 0, gmtoff: 0, zone: UTC
 $ uname -a
 FreeBSD bayonetta.local 9.0-CURRENT FreeBSD 9.0-CURRENT #5 r205310:
 Sat Mar 20 01:32:51 PDT 2010
 gcooper@bayonetta.local:/usr/obj/usr/src/sys/BAYONETTA  amd64
 
     I've included a modified version of the originally provided test
 stimulus which does essentially the same thing, but instead uses
 INT32_MAX instead of a hardcoded value and is fixed as per my best
 understanding of style(9).
 Thanks,
 -Garrett
 
 -----------------
 
 #include <errno.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <time.h>
 
 void t_inspect(time_t t)
 {
 	struct tm *tp;
 	errno =3D 0;
 	tp =3D gmtime(&t);
 	printf("t: %ld, tp: %p errno: %d\n", t, tp, errno);
 	if (tp)
 		printf("sec: %d, min: %d, hour: %d, mday: %d, mon: %d, "
 		    "year: %d, wday: %d, yday: %d, isdst: %d, gmtoff: %ld, "
 		    "zone: %s\n", tp->tm_sec, tp->tm_min, tp->tm_hour,
 		    tp->tm_mday, tp->tm_mon, tp->tm_year, tp->tm_wday,
 		    tp->tm_yday, tp->tm_isdst, tp->tm_gmtoff, tp->tm_zone);
 }
 
 int main(void)
 {
 	time_t t =3D INT32_MAX;
 	t_inspect(t-1);
 	t_inspect(t);
 	t_inspect(t+1);
 	return 0;
 }
>Unformatted:
