svn commit: r292777 - in head: lib/libc/sys sys/kern

Bruce Evans brde at optusnet.com.au
Tue Dec 29 14:10:00 UTC 2015


On Tue, 29 Dec 2015, Dmitry Chagin wrote:

> So, my point was:
> a)  for a long time we have broken settimeofday() which does not allow us
> to set the system time before the Epoch

We still have a broken settimeofday that doesn't allow us to set the system
time to the Epoch in the Western hemisphere if the clock is on local time,
and doesn't allow as to set the system time to a year > 9999.  More precisely
it does allow us to set these and usually panics on x86 before completing.

> b) as you already mentioned POSIX doesn't require times before the Epoch to
> work

In fact, the representation of times is undefined for times before the
Epoch in general.

The specification of clock_settime() is interesting.  At least in an
old POSIX-2001 draft, It is required to set to the specified time and is
not limited to the current time, whatever that is.  It is only required
to work for CLOCK_REALTIME.  It is required to fail if the specified
time is outside of the "legal range" for the clock id.  "legal range"
is bad wording and is unspecified.

> с) Linux does not allows negative seconds also

Old (~2004) versions of Linux seem to have less error checking for i386
settimeofday() FreeBSD then, so they seem to allow it.  The implementation
seems to be:
- copy the requested value to the kernel software time without much error
   checking.  Don't touch the hardware yet
- update the RTC every 11 minutes if the clock is externally synchronized.

So with 64-bit time_t anyone could easily set the time to year +-292g, or
just to year +-10k.  The AT RTC cannot represent this, and it is difficult
to make it try since it is difficult to find external servers running that
far off the current time.  With 32-bit time_t the range is 1906-2037.
Linux seems to have no range checking for the conversion to BCD, but it
doesn't panic because the BCD macros are expressions.  These macros of
course don't work for arbitrary inputs.  They just convert valid but
unusual years to garbage.  Before that, negative times are converted to
garbage using a type pun: set_rtc_mmss(xtime.tv_sec) starts with a time_t,
but the function takes an unsigned long.  So 1 second before the Epoch
becomes year +584g.  The usual divisions by 60 are used to reduce the
type-punned time.  Since it is unsigned, these now give garbage in-range
values.

> d) we have settimeofsay(2) that consistent with POSIX and in my
> understanding phrase "The time is expressed in seconds and microseconds
> since midnight (0 hour), January 1, 1970." is a strict definition, which
> prohibits time before the Epoch

TImes before the Epoch give undefined behaviour, so they are allowed to
work.  They are even allowed to work better than times after the Epoch,
since they can have any representation and are not require to be missing
support for leap seconds.

> I do not understand why we should have our own (separate from the rest
> world) behavior.

It would be good to not have such broken bounds checkng as the rest of
the world.

Updating the AT RTC synchronously in settimeofday() is already more
significantly different than limiting the range of accepted times.  One
reason that Linux updates asynchronously is that a correct synchronous
update (which FreeBSD doesn't do) requires waiting for a second or two.
The asynchronous update gives the usual problems handling errors --
even if the interrupt handler detected representation errors, it wouldn't
be able to return them to settimeofday().  So errors of a measly 292g
years go unreported.

Bruce


More information about the svn-src-head mailing list