This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Fifth draft of the Y2038 design document


Hi Arnd,

On Wed, 22 Feb 2017 16:39:53 +0100, Arnd Bergmann <arnd@arndb.de>
wrote :

> On Wed, Feb 22, 2017 at 9:05 AM, Albert ARIBAUD <albert.aribaud@3adev.fr> wrote:
> > Hi all,
> >
> > I have produced a fifth draft of what will eventually become the Y2038
> > design document:
> >
> > https://sourceware.org/glibc/wiki/Y2038ProofnessDesign?rev=115
> >
> > Relative to the previous draft:
> >
> >  * It makes explicit that the implementation should allow the same
> >    application source code to build unchanged whether the default for
> >    time size is 32-bit (_TIME_BITS undefined or unequal to 64) or
> >    64-bit (_TIME_BITS defined equal to 64).
> >
> >  * Security issues considerations have been added (thanks to Carlos
> >    O'Donnel).
> >
> >  * Timestamps and IOCTLs sections have been expanded.
> >
> >  * Implementation examples for types has been added.
> >
> >  * Implementation examples for APIs has been added.
> >
> > As always, comments welcome.  
> 
> I found a few minor inaccuracies:
> 
> You have classified sched_rr_get_interval() as y2038-compatible, but
> getrusage() as incompatible. I think these are both in one category,
> either incompatible or a third category: we pass only intervals
> here, so there won't be an overflow but redefining timeval still results
> in an incompatible ABI, unless the structures are redefined in terms
> of 32-bit types instead of time_t/timeval/timespec.

Actually, sched_rr_get_interval deserves a fourth category, known as
'in a quantum state', because depending on where you look in the
document, it is either compatible or incompatible, due to a copy-paste
failure. :)

Joke apart, thanks for pointing it out and raising the point. My
opinion is as follows:

1. Right now sched_rr_get_interval takes a struct timespec as an
   argument;

2. One goal of the project is that source code which works with 32-bit
   time should work unchanged if compiled with default time size set to
   64 bits;

3. This means the 64-bit version of sched_rr_get_interval should keep
   explecting a (now 64-bit) 'struct timespec';

4. This in turn makes the ABIs of the 32- and 64-bit versions of
   sched_rr_get_interval mutually incompatible, since the actual types
   involed would be either the 32-bit time 'struct timespec' or the
   64-bit time 'struct timespec64';

5. Ergo, sched_rr_get_interval should be classified as
   Y2038-incompatible.

> I've discussed the kernel side for "Y2038-incompatible socket
> timestamping" with Deep a while ago, and I think we came to a
> new conclusions for what would be the best approach. I'll let her
> comment here.
> 
> For "Y2038-compatible types", please clarify whether time32_t
> and time64_t (and related types) are internal-only types or visible
> to applications through header files. I assume they are internal
> only, but it is not 100% clear. Related to that, what is the expected
> definition of time32_t on architectures that never had a 32-bit time_t,
> such as existing 64-bit architectures? Is it left undefined and
> all code referring to time32_t compiled conditionally?

(written after reading Joseph's reply, and type names adapted
accordingly)

Yes, there would be two internal types, __time_t and __time64_t with
sizes invariant with respect to default type size, whereas time_t, in
the user facing public API, would be defined as either __time_t or
__time64_t depending on which time bit size the user code would choose

For instance, with difftime:

- the existing, 32-bit-time version would be defined as 
	double __difftime(__time_t time1, __time_t time0) ...

- the new, 64-bit-time version would be defined as 
	double __difftime64(__time64_t time1, __time64_t time0);

- for user code which does not define _TIME_BITS=64 at compile time,
  GLIBC would emit [what amounts to] the following declaration:
	double __difftime(__time_t time1, __time_t time0);
	typedef __time_t time_t;
	__REDIRECT(difftime,(time_t time1, time_t time0),__difftime)
  so that when the user code would say
  	time_t t1, t2; ...; difftime(t1, t2);
  this would amount to
  	__time_t t1, t2; ...; __difftime(t1, t2);

- for user code which defines _TIME_BITS=64 at compile time,
  GLIBC would emit [what amounts to] the following declarations:
	double __difftime64(__time64_t time1, __time64_t time0);
	typedef __time64_t time_t;
	__REDIRECT(difftime,(time_t time1, time_t time0),__difftime64)
  so that when the user code would say
  	time_t t1, t2; ...; difftime(t1, t2);
  this would turn into
  	__time64_t t1, t2; ...; difftime64(t1, t2);

(should I rename the current __time_t to a more explicit __time32_t?)

As far as 64-bit architectures are concerned:

- pure 64-bit architectures already have a 64-bit time_t, and are out
  of the scope of my project; a 64-bit GLIBC is assumed to be Y2038-
  compatible as far as APIs go (there may be bugs though; again, if
  I see any, I'll raise an GLIC issue but outside of this project).

- this leaves the case of a 64-bit architecture kernel providing a
  32-bit ABI to 32-bit code. I am not planning on supporting such a
  scenario.

> In "Y2038-compatible struct timespec", replace "microseconds"
> with "nanoseconds.

Oops. Fixed in revision 118.

> Also, it's worth pointing out the known problems
> with the padding:
> - on big-endian systems, any code doing a variation of
>    "struct timespec ts = { seconds, nanos };" is broken because
>   it assigns the nanoseconds to the wrong struct member.
>   The example code is nonconforming as neither POSIX nor C11
>   require a particular order of the struct members, but I could also
>   easily find examples of existing programs doing this. Note that
>   NetBSD, OpenBSD and Windows have no padding but do use
>   64-bit time_t.
> - If the padding is uninitialized, we have to explicitly zero it before
>   calling a kernel function that assumes the 64-bit layout. This can
>   be done in glibc before calling into the kernel, or at the kernel
>   entry (where my last patch set does it), but it is awkward either
>   way.
> Unfortunately, there doesn't seem to be a good solution here
> for either of the two problems. Maybe someone else has more
> ideas. Using a pointer type for the padding would at least
> cause a compile-time warning for broken code, other solutions
> might require GCC extensions or break C11 in another way.

Agreed on the whole line, and I will add these points in the document.

However, this makes me consider an option which would keep source code
as happy as possible: keep tv_nsec a long even in struct timespec64
(so the struct would be 12 bytes: 8-byte tv_sec, 4-byte tv_nsec).

It would be ABI-incompatible with 64-bit code, but would conform to
Posix, and the same exact user source code would then compile equally
well in all three cases: 32-bit time 64-bit time on 32-bit arch, 64-bit
arch, including the struct initializers you mentioned above.

There would be a rough edge left when running 32-bit arch, 64-bit time
user code over a 64-bit arch GLIBC and kernel, because then we'd have
to copy between 64-bit and 32-bit nanosecond fields, but then again,
it is not a scenario I am aiming for.

> I'll comment on the kernel/glibc incompatibilities section tomorrow,
> need to collect my thoughts there some more.

Thanks!

>      Arnd

Cordialement,
Albert ARIBAUD
3ADEV


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]