Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 21 Apr 2017 21:53:21 +1000 (EST)
From:      Bruce Evans <brde@optusnet.com.au>
To:        Hans Petter Selasky <hps@selasky.org>
Cc:        Bruce Evans <brde@optusnet.com.au>, Michael Tuexen <tuexen@freebsd.org>,  Cy Schubert <Cy.Schubert@komquats.com>, src-committers@freebsd.org,  svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   Re: svn commit: r317208 - head/sys/netinet
Message-ID:  <20170421211348.I2311@besplex.bde.org>
In-Reply-To: <1920616c-1993-07d5-4855-73264dce0980@selasky.org>
References:  <201704210143.v3L1h99s037727@slippy.cwsent.com> <20170421131041.G966@besplex.bde.org> <8BBC38A0-DDBA-4C04-9654-98755B3E4E13@freebsd.org> <20170421173453.J1735@besplex.bde.org> <1920616c-1993-07d5-4855-73264dce0980@selasky.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On Fri, 21 Apr 2017, Hans Petter Selasky wrote:

> On 04/21/17 10:10, Bruce Evans wrote:
>> ...
>> i386 should use time_t = uint32_t to fully support years 2038-2106 instead
>> of time_t = int32_t to partially support years 1902-1970
>>   (even time 0 (the Epoch) and other early hours in 1970 are not fully
>>   supported now and would be broken by unsigned time_t, since subtraction
>>   of the timezone offset from 0 gives negative values with signed time_t
>>   and overflowing values with unsigned time_t).  (time_t)-1 is special,
>>   so the time 1 second before the Epoch cannot work with signed time_t.
>>   This value works better with unsigned time_t because it is not in the
>>   middle of the range, but times before the Epoch are just unrepresentable
>>   with unsigned time_t.
>> 
>> Changing the signedness of time_t would break the ABI less than changing
>> its size, but it still causes problems with buggy software which assumes
>> that time_t is signed or encodes special values in it.  Negative times
>> are at best unspecified by POSIX.  They give a large range of magic out
>> of band values below 0, provided nothing assumes that the system is better
>> designed than POSIX so supports times before the Epoch.  Even the Standard
>> C library is not that bad, except POSIX forces a bad design for time_t so
>> mktime() and friends are restricted to times.  If time_t is unsigned,
>> then no times before the Epoch can work, and if it is signed then times
>> before
>> the Epoch are unportable.
> ...
>
> Your proposal to change time_t to unsigned type is potentially dangerous in 
> combination with NTP, where negative time deltas may occur. Consider existing 
> code like this, both in three and outside the tree.

Yes, I already pointed out that there is a lot of buggy software out there.
Maybe ntp understansd time_t, but its users might not.

> static time_t last;
> time_t now = time();
> time_t delta
>
> delta = now - last;

This assumes something like POSIX plus signed time_t.  In standard C,
time_t can be almost anything so the subtraction is invalid.  You have
to use difftime().  difftime() was heavyweight when C was young, but
now with time_t = double and difftime() inline, it is probably lighter
and faster than POSIX timespecs.  difftime(x, y) can be just x - y
in 64-bit double precision, while timespecs may be bloated to 128 bits
and are in a non-binary format that is hard to subtract.  Timespecs
do have a larger range.  The precision of 64-bit double is only enough
for microseconds resolution over 272 years.  So it can easily replace
timevals but not timespecs.

In original POSIX, time_t could be any arithmetic type.  This allowed
it to be double.  Good for userland but bad for kernels and sysctls,
so few or no POSIX systems made it double.  time_t is now integral
in POSIX.  It could be unsigned the last time I looked.

> if (delta > 0) {
>   /* do something */
> } else {
>   /* ignore */
> }
>
> If time_t is now unsigned, then the check above becomes true for alomost all 
> values of time_t, except zero, which is wrong!

Who would write such buggy code? :-)  Practical POSIX code near ntp would
probably use timespecs or timevals, and they can't be subtracted or compared
easily anyway.  FreeBSD has macros for this, but they are unportable and
not as easy to use as difftime or simple conversion to floating point
(except for timespecs, the conversion is not so simple since it may lose
resolution).

> Can C-compilers assert signedness of a variable?

Yes, but they don't since this would find too many errors and non-errors
for conversions.

> I propose, utime_t -> unsigned time and stime_t -> signed time.

That would just increase unportability and not help to avoid changing
the size of time_t in standard APIs that require it.

With another hat on, I lecture about the error of using unsigned types
except in emergency.  int32_t time_t rollover in 2038 is getting a bit
closer to an emergency.  Even for variables and types that were
misdesigned to be unsigned, it is easy to forget this and use them in
things like delta-calculations which require signed types.

Bruce



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