NetBSD Problem Report #11545

Received: (qmail 27818 invoked from network); 22 Nov 2000 02:03:27 -0000
Message-Id: <200011132208.eADM84O21018@kaakeli.ssh.fi>
Date: Tue, 14 Nov 2000 00:08:04 +0200 (EET)
From: Tero Kivinen <kivinen@ssh.fi>
To: gnats-bugs@gnats.netbsd.org
Subject: gmtime does not work after 2038
X-Send-Pr-Version: 3.95

>Number:         11545
>Category:       y2k
>Synopsis:       gmtime returns year 1901 if trying to use time > 0x80000000
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    y2k-manager
>State:          closed
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Wed Nov 22 02:04:01 +0000 2000
>Closed-Date:    Sun Oct 27 20:17:24 +0000 2002
>Last-Modified:  Sun Oct 27 20:17:24 +0000 2002
>Originator:     Tero Kivinen
>Release:        NetBSD 1.5_ALPHA 2
>Organization:
SSH Communications Security
>Environment:
System: NetBSD kaakeli.ssh.fi 1.5_ALPHA2 NetBSD 1.5_ALPHA2 (KAAKELI) #39: Fri Oct 13 03:12:52 EEST 2000 kivinen@kaakeli.ssh.fi:/usr/src/sys/arch/i386/compile/KAAKELI i386


>Description:

	If gmtime is given a time_t that is negative (i.e unix time
	after 2038), then it returns year as 1901. This breaks for
	example the perl HTTP::Cookie library, as for example the
	www.google.com sets cookie like this:

	Set-Cookie: PREF=ID=15d4258c1f04851e:TM=973465320:LM=973465320;
	domain=.google.com; path=/; expires=Sun, 17-Jan-2038 19:14:07 GMT

	And when HTTP::Cookie tries to convert that 17-Jan-2038
	19:14:07 to unix time it will fail and print out error
	message.

	Also most of the commercial y2k statements define programs to
	be y2k safe only if they work up to year 2100. This means that
	netbsd programs are NOT y2k safe in that sense, if they use
	any gmtime etc functions. 

>How-To-Repeat:

	#include <stdio.h>
	#include <stdlib.h>
	#include <time.h>

	int main(int argc, char **argv)
	{
	  struct tm *t;
	  time_t c;

	  c = 0x80000000;
	  t = gmtime(&c);
	  printf("%d-%02d-%02d %02d:%02d:%02d\n",
		 t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
		 t->tm_hour, t->tm_min, t->tm_sec);
	  return 0;
	}

>Fix:

	Proper fix would be to define new time_t type (ltime_t?) that
	would be 64-bits and start using that. Another easier fix
	would be change the time_t to be unsigned instead of signed,
	but this might break some programs. Easiest fix would be to
	modify the lib/libc/time/localtime.c:timesub() so that it will
	interpret the time_t as unsigned internally and return years
	bigger than 2038 instead of years smaller than 1970 if
	negative time_t values are used.
>Release-Note:
>Audit-Trail:

From: Robert Elz <kre@munnari.OZ.AU>
To: Tero Kivinen <kivinen@ssh.fi>
Cc: gnats-bugs@gnats.netbsd.org
Subject: Re: y2k/11545: gmtime does not work after 2038 
Date: Wed, 22 Nov 2000 15:39:16 +0700

     Date:        Tue, 14 Nov 2000 00:08:04 +0200 (EET)
     From:        Tero Kivinen <kivinen@ssh.fi>
     Message-ID:  <200011132208.eADM84O21018@kaakeli.ssh.fi>

   | 	Proper fix would be to define new time_t type (ltime_t?) that
   | 	would be 64-bits and start using that.

 Yes, at some time that might be needed.  It is a big change though,
 and exactly what the format would be is not clear - certainly we don't
 need a 64 bit offset of seconds from 1970 (not even 63 bit if it is
 signed), the universe will have ended before then...

 So, almost all suggestions for 64 bit time_t replacements also store
 sub-seconds (perhaps down to pico-seconds).  (ie: use scaled ints).

   | Another easier fix
   | 	would be change the time_t to be unsigned instead of signed,

 I did that in 4.2BSD before it was released.   The change didn't
 last long - it broke so much, as to be unsupportable.  The breakage
 wasn't mostly in applications expecting signed time_t (there may have
 been some of that, but it was minor) - the breakage was in ctime()
 (localtime()) which couldn't cope with time_t t = 0; when that was
 done (if you're in a timezone anywhere west of Greenwich - so it
 had never bothered me....).   That is, for time_t 0 people were used
 to seeing some time in Dec 31, 1969, and were real upset when 2106
 (or whatever it is) turned up instead.

 That could be fixed in localtime() but at the time it seemed safer
 to simply make time_t back to being signed.

 And in any case (this was all pre POSIX of course, and ANSI C as well)
 it was never clear that being able to represent times before 1970
 shouldn't be possible ... ie: time_t t = - 100 * 86400 ought be 100
 days before the start of 1970, perhaps.   Or maybe not...

   | 	but this might break some programs. Easiest fix would be to
   | 	modify the lib/libc/time/localtime.c:timesub() so that it will
   | 	interpret the time_t as unsigned internally and return years
   | 	bigger than 2038 instead of years smaller than 1970 if
   | 	negative time_t values are used.

 A safer fix, that would probably bother less people, would be to
 set the range of a time_t to be from (say) 1964 .. 2100, so there
 are about 6 years of negative values, and 130 years of positive
 values.

 Most likely that would bother almost no-one.   But it would be worth
 asking about this on the tz list, where the people who really care
 about time representations, and conversions, hang out.  tz@elsie.nci.nih.gov

 kre


From: Tero Kivinen <kivinen@ssh.fi>
To: Robert Elz <kre@munnari.OZ.AU>
Cc: gnats-bugs@gnats.netbsd.org
Subject: Re: y2k/11545: gmtime does not work after 2038 
Date: Wed, 22 Nov 2000 15:37:38 +0200 (EET)

 Robert Elz writes:
 >   | 	Proper fix would be to define new time_t type (ltime_t?) that
 >   | 	would be 64-bits and start using that.
 > Yes, at some time that might be needed.  It is a big change though,
 > and exactly what the format would be is not clear - certainly we don't
 > need a 64 bit offset of seconds from 1970 (not even 63 bit if it is
 > signed), the universe will have ended before then...

 True. 

 > So, almost all suggestions for 64 bit time_t replacements also store
 > sub-seconds (perhaps down to pico-seconds).  (ie: use scaled ints).

 Pico (1E-12) is too short... That would give us only 0.58 years... I
 think nano (1E-9) is ok, it will give us 584 years. Of course it would
 be better to define it starting from some other value than 1970 if we
 are going to change the format anyways, i.e change the resolution to
 micro (1E-6) and start it 2000 years before year 2000 (i.e year -1,
 because somebody claims that year 0 does not exist :-) That would give
 use time that is ok up to year 584942, i.e then we only need to take
 care of the Y10K and Y100K problems, but not Y1M problem...

 Microsecond resolution is propably going to be enough when we are
 talking about the absolute real time, and timeval is already using
 that resolution anyways. 

 Another possibility is to start using structure like timespec/timeval,
 and make it to be signed 64-bit second counter from year 1970, and
 32-bit nanosecond counter inside that second. 

 > A safer fix, that would probably bother less people, would be to
 > set the range of a time_t to be from (say) 1964 .. 2100, so there
 > are about 6 years of negative values, and 130 years of positive
 > values.

 I think that would be safest and best kludge to fix the problem now
 before making the real fix (changing to use 64 bit time). 

 > Most likely that would bother almost no-one.   But it would be worth
 > asking about this on the tz list, where the people who really care
 > about time representations, and conversions, hang out.  tz@elsie.nci.nih.gov

 Ok.
 -- 
 kivinen@ssh.fi                               Work : +358 303 9870
 SSH Communications Security                  http://www.ssh.fi/
 SSH IPSEC Toolkit                            http://www.ssh.fi/ipsec/

From: Robert Elz <kre@munnari.OZ.AU>
To: Tero Kivinen <kivinen@ssh.fi>
Cc: gnats-bugs@gnats.netbsd.org
Subject: Re: y2k/11545: gmtime does not work after 2038 
Date: Wed, 22 Nov 2000 22:02:15 +0700

     Date:        Wed, 22 Nov 2000 15:37:38 +0200 (EET)
     From:        Tero Kivinen <kivinen@ssh.fi>
     Message-ID:  <200011221337.PAA21749@torni.hel.fi.ssh.com>

   | Pico (1E-12) is too short...

 Hmm - yes, so it is...

   | Microsecond resolution is propably going to be enough

 Probably, though an issue that matters, is that to avoid growing
 inodes, the entire time thing needs to fit in 64 bits, to be able
 to record access/modify/change time on files.   Microseconds are
 already getting to be pretty long, in the forseeable future it
 might actually be possible to make useful changes to files in less
 than a microsecond, then that resolution wouldn't really be enough.
 Maybe 1E-8 (though not a unit with a name) might be good - 5800
 years should be plenty (+/- 2900 perhaps).

   | Another possibility is to start using structure like timespec/timeval,
   | and make it to be signed 64-bit second counter from year 1970, and
   | 32-bit nanosecond counter inside that second.

 Then it won't fit in the space available in inodes.

 kre


From: Andrew Brown <atatat@atatdot.net>
To: Tero Kivinen <kivinen@ssh.fi>
Cc: gnats-bugs@gnats.netbsd.org
Subject: Re: y2k/11545: gmtime does not work after 2038
Date: Wed, 22 Nov 2000 12:06:49 -0500

 >	If gmtime is given a time_t that is negative (i.e unix time
 >	after 2038), then it returns year as 1901. This breaks for
 >	example the perl HTTP::Cookie library, as for example the
 >	www.google.com sets cookie like this:

 that's because time is stored as a signed value, so once the high bit
 goes on, it falls back to the beginning: Fri, 13-Dec-1901 20:45:52 GMT.

 >	Set-Cookie: PREF=ID=15d4258c1f04851e:TM=973465320:LM=973465320;
 >	domain=.google.com; path=/; expires=Sun, 17-Jan-2038 19:14:07 GMT
 >
 >	And when HTTP::Cookie tries to convert that 17-Jan-2038
 >	19:14:07 to unix time it will fail and print out error
 >	message.

 then that module is in error.

    % date -u -r 2147368447 +"%a, %d-%b-%Y %T %Z"
    Sun, 17-Jan-2038 19:14:07 GMT

 >	Also most of the commercial y2k statements define programs to
 >	be y2k safe only if they work up to year 2100. This means that
 >	netbsd programs are NOT y2k safe in that sense, if they use
 >	any gmtime etc functions. 

 funny...and all this time i thought that y2k safe meant it would
 survive the crossover into the year 2000.

 -- 
 |-----< "CODE WARRIOR" >-----|
 codewarrior@daemon.org             * "ah!  i see you have the internet
 twofsonet@graffiti.com (Andrew Brown)                that goes *ping*!"
 andrew@crossbar.com       * "information is power -- share the wealth."
State-Changed-From-To: open->closed 
State-Changed-By: chs 
State-Changed-When: Sun Oct 27 12:12:34 PST 2002 
State-Changed-Why:  
since time_t has historically been signed, if one uses a negative value, 
one should expect that to be before the epoch.  I'll also note that 
the time in the example is actually 0x7ffe3dff, which isn't even negative. 
further, solaris, hpux and aix all return a date in 1901 for the given 
test program, so we're conforming to industry practice.  in short, 
the existing code is fine. 
>Unformatted:

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2007 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.