Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 28 Feb 2019 00:21:53 +1100 (EST)
From:      Bruce Evans <brde@optusnet.com.au>
To:        everton.win32@gmail.com
Cc:        bugs@freebsd.org
Subject:   Re: [Bug 236065] TimeStamp Overflow 2106 year
Message-ID:  <20190227223837.D2208@besplex.bde.org>
In-Reply-To: <bug-236065-227@https.bugs.freebsd.org/bugzilla/>
References:  <bug-236065-227@https.bugs.freebsd.org/bugzilla/>

next in thread | previous in thread | raw e-mail | index | archive | help
On Tue, 26 Feb 2019 bugzilla-noreply@freebsd.org wrote:

> https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236065

> I work doing tests, and I found one possible in a decentralized system that is
> used worldwide.
> I want to simulate a specific date in the 22nd century;
> however when I define the system with the date: 01/01/2106 00:00;
>
> the system reports an error.

This is not supported.  On x86 systems, the hardware clock only has a
trustable range of 100 years.  This range currently defaults to
1970-2069 for all arches whose clocks have a range of 100 years.  Old
versions that had to work before Y2K did the same thing in driver code
on at least x86.  This regressed to to blindly adding 2000 in driver
code in FreeBSD7-[7-8] (perhaps the same in FreeBSD-6 and late
FreeBSD-5).  This gave the different range of 2000-2099.  This advanced
towards the previous version by changing the range to 1980-2079 in
FreeBSD-[9-10].  Advancing the range by 10 or 30 years 50 years before
a change is needed mainly breaks testing past dates for young people's
birthdays and takes longer mail to describe.  1970 is a much better
start for a 100-year range since it is the POSIX Epoch and covers a
few more birthdays.  1980 is politically incorrect since msdosfs uses
it.  This was finally improved relative to what old versions did in
FreeBSD-[11-current] by removing the adjustments in driver code so
that the better machine-independent code is used.

The machine-independent code also adjusts for years 70-199.  This will
start supporting clocks with a single bit for the century in 2070.
Dates before 1970 are disallowed in the MI code even for clocks that
support them.

x86 clocks actually have a century register, so can do better than clocks
with a century bit, but FreeBSD doesn't trust this register.  You can try
it using the unsupported option USE_RTC_CENTURY.  Expect bugs using this
option.  The bugs are hard to test, and are especially likely in testing
where you set the year to anything except the 21st century.  The BIOS
might reset the century to 20.  The FreeBSD clock code is not very robust,
except on i386 where it limits the year to 1970-2037.  Know bugs in this
include not being able to represent local time for the Epoch in some
timezones.  Then for the Epoch time of 0 representing the start of 1970,
the local time is 1969 in some timezones.  Writing this 1969 to x86 clocks
truncates it to 69, which means 2069 in local time on the next boot.  But
it means 2070 in UTC on the next boot.  2070 is outside of the supported
range, and it is unclear what happens.  At best it gets converted back to
1970.

2106 is a good date to warm up with.  It is when 32-bit unsigned time_t
overflows.  There is too much broken clock code which assumes that time_t
is signed to easily extend the range if 32-bit signed time_t by changing
it to unsigned.

> if I enter another date, for exemple: 01/01/2105 00:00
> the freebsd allows it to be changed.
>
> but after the reboot. it sets to: 01/01/2005 00:00;

You just found a bug after in the non-robust MI clock code.  i386 doesn't
have this bug, since it doesn't allow setting times after 2037, since
32-bit singed time_t can't represent times a little later in 2038 and
stopping at the end of 2037 gives a safety margin.  On amd64, the kernel
allows setting times that the driver or hardware clock can't handle.  It
asks the driver to write 2105, but the driver only writes 05.  Then on the
next boot, this means 2005.

Don't worry about this for tests.  Just set the time early in the boot, and
also set it back to the the current time before rebooting in case the BIOS or
other OSes don't like it being later.

I don't know of anything that immediately breaks similar testing in 2106
or even at the end of 64-bit time_t in 292 billion years.  Set the time
early in the boot using date(1) or similar, and don't let ntpdate or anything
else on the network see this time.  This write garbage to the x86 clock, but
the x86 clock is write-only until the next boot.

> I found some information on:
>
> https://en.wikipedia.org/wiki/Year_2038_problem

2038 is just the special limit for 32-bit signed time_t which only some
systems use.

> there is a possibility that I compile the system to use the size uint64?
>
> according to the wikipedia topic:
>
> FreeBSD uses 64-bit time_t for all 32-bit and 64-bit architectures except
> 32-bit i386[11].

You must already be using 64-bit time_t to reach 2105,

> if the field actually has 64 bits, it can even be used after 2107 (which is the
> date I need);

For another 292 billion years.

If there really is a 2106 limit on amd64, then it must be from using 32-bit
unsigned seconds counts somewhere.  I haven't looked at what user library
code does with this lately.

I did a quick check on amd64, in single user mode with no disks mounted
rw (to prevent clobbering file times).  Setting the date to 2106 just
works, at least with a very old userland.  Setting the date to the
last second in 9999 works too.  date(1) doesn't support setting
centuries after the 99th, but it works for displaying them after the
time advances from the end of 9999 to 10000.

Bruce



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20190227223837.D2208>