Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 24 Jun 2016 20:55:01 +1000 (EST)
From:      Bruce Evans <brde@optusnet.com.au>
To:        Peter Wemm <peter@wemm.org>
Cc:        freebsd-arch@freebsd.org
Subject:   Re: PowerPC 64-bit time_t
Message-ID:  <20160624194454.D1013@besplex.bde.org>
In-Reply-To: <575A48D3.3090008@wemm.org>
References:  <3FB65E20-0376-4041-86DE-F8CAB7F37314@freebsd.org> <20160609193128.GB34204@spindle.one-eyed-alien.net> <575A48D3.3090008@wemm.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On Fri, 10 Jun 2016, Peter Wemm wrote:

> On 6/9/16 3:31 PM, Brooks Davis wrote:
>> On Thu, Jun 09, 2016 at 01:41:52PM -0400, Justin Hibbits wrote:
>>> At the devsummit earlier today I mentioned for FreeBSD 12 wanting 64-
>>> bit time_t across the board.  It was pointed out that the only ones

FreeBSD-12 certainly doesn't want the bloat and ABI breakage of 64-bit
time_t.  The 32nd bit is not needed before FreeBSD-23 in 2038.  The 33rd
bit is not needed before FreeBSD-57 in 2106.

>>> with 32-bit time_t are i386 and powerpc (32-bit).  I've made the
>>> changes necessary for at least kernel (world is still building right
>>> now), but it's obviously an ABI and KBI incompatible change.
>>> Addressing KBI is a nonissue, as that's expected to break at major
>>> releases.  ABI is another issue.  I'm unsure how to properly address
>>> ABI breakage -- bumping libc's .so version, or reversion all symbols
>>> that use something with time_t, or something else.  If I can address
>>> it before the code freeze, it could be done for FreeBSD 11, which
>>> leaves about 6 hours from now.
>> 
>> For i386, the only practical option is going to be a new TARGET_ARCH and
>> likely ELF machine type.

The only practical option for i386 is to change to unsigned time_t before
2038 and hope that i386 goes away before that runs out in 2106.  Changing
to uint32_t time_t mainly requires doing something with times before the
Epoch.  These are unsupported in POSIX, but are supposed to work back to
1902 with int32_t in FreeBSD, except 1 second before the Epoch is the
same as the error code (time_t)(-1) so it doesn't work right.

> I investigated this when I did 64 bit time_t on amd64 - the chances of 
> getting this to work on i386 are ... problematic.. to say the least.
>
> A short summary of the issues for i386:
>
> * sparc64, amd64 and ia64 were "easy" because there was an actual register to 
> implement it.  Calling conventions plaster over vast quantities of sins and 
> carelessness and make it Just Work by in spite of it. You forget a function 
> prototype and it still works.  i386 has to do it with "long long" which 
> requires discipline. Miss a prototype and it falls flat.

On 64-bit arches, most of the space bloat for 64-bit time_t is unavoidable
because:
- args are expanded to 64 bits
- struct timeval was originally misdesigned as having members tv_sec and
   tv_usec of type long.  These longs were basically an implementation of
   int_least32_t before <stdint.h> existed.  tv_usec only needs to go up
   to 10**9, so it should have type precisely int_least32_t or possibly
   int32_t to give an invariant ABI.  POSIX copied this mistake and added
   many more when it made the mistake of inventing struct timespec.  ts_nsec
   stil has type long.  This gives the stupid ABI that on 64-bit arches
   with 32-bit time_t, struct timespec starts with a 32-bit time_t, then
   has 32 bits of padding, then has a 64-bit long with only 32-bits used.
   Later, POSIX broke the ABI for struct timeval to match -- it changed
   'long tv_sec' to time_t tv_sec.
So using 64-bit time_t costs little on 64-bit arches.

> eg:  if you miss the prototype for a function returning time_t the language 
> defaults the return value to "int".  On ia64, amd64 and sparc64, this is 
> actually returned as a 64 bit value (native register) and it actually gets 
> the full 64 bit value.  For i386, this doesn't happen - you always get 
> truncation. You won't find out until it actually matters.  This problem will 
> keep turning up forever.  The top half will be returned in the %edx secondary 
> return register and will be ignored.

Forever only afer 2038 :-).  And between 2038 and 2106, 32-bit time_t will
still almost work without making it officially unsigned -- discarding the
top half still gives a value that is correct when the sign bit is
interpreted as a value bit, provided it was set using overflow magic as
a value bit.

> * classic 3rd party code used "long" and "time_t" interchangeably.  We get 
> away with this on ia64, amd64 and sparc64 just fine.  This will also lead to 
> truncation on i386 with 64 bit time_t when it matters.
>
> * Sloppy prototyping leads to stack misalignment on i386 with "long long". 
> Arguments are rounded up to 32 bit alignment, so char/short/int/long 
> confusion on i386 for function calling protocol mostly is repaired as a side 
> effect.  'long long' doesn't get this treatment for function calls - any 
> sloppiness will be punished with arguments being shifted.  Unlike the 
> truncation above, this is pretty quick to find.  You won't have to wait 5-10 
> years for them to shake out.
>
> Most of the FreeBSD base tree was fixed for this during the Alpha era (which 
> used "int" for time_t on a 64 bit platform because mktime() in libc wasn't 64 
> bit safe at all).  However, when you go near ports and 3rd party code the 
> situation is rather grim.  The code out there is terrible.
>
> I maintain that while we got away with it for machines that the calling 
> conventions masked the pain for sloppy and legacy programming, this is not 
> the case for architectures like i386.  The pain will never end.

I agree.

> Do you want to be the one who has to explain why something like openssl isn't 
> rejecting expired certificates because openssl happens to confuse long/time_t 
> internally somewhere in the X509 validator?  (Note: I'm not saying it is 
> broken, but I don't have a hard time imagining that it could..).

The question is if changing 32-bit time_t to unsigned is also too painful.
I think it won't make much difference until 2038 when the 32nd bit is
actually used.

> Also, don't forget all the compat_freebsd32 layers.  You'll have to realign 
> all the arguments because 'long long' is 32 bit aligned, and a 64 bit long 
> (aka time_t) is 64 bit aligned.

Also, they need to do something better than truncation to convert 64-bit
time_t to 32-bit time_t.  The only reasonable thing to do between 2038
and 2106 is to use uint32_t for the compatibility layers and teach old
applications to expect this.

Then there are the compat_{linux,svr*} layers.  All representations and
conversions must be compatible with whatever the emulated OS does.

> I'm sure it could be done for a science project, but I wouldn't want to go 
> anywhere near it for something that would be relied upon. This would be a 
> project that gives gifts that will keep on giving.

Bruce



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