This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: Fifth draft of the Y2038 design document
On Wed, Feb 22, 2017 at 4:39 PM, Arnd Bergmann <arnd@arndb.de> wrote:
> I'll comment on the kernel/glibc incompatibilities section tomorrow,
> need to collect my thoughts there some more.
For build-time dependencies, any changes we do to the kernel
headers should only add things for new glibc but leave the
existing definitions unchanged as long as _TIME_BITS is not
set to 64 on a 32-bit architecture.
In the few cases that can't be handled by simply adding new
definitions, we need to replace e.g.
#define SIOCGSTAMPNS_OLD 0x8907
with something like
#define SIOCGSTAMPNS_OLD 0x8907
#define SIOCGSTAMPNS_TIME64 _IOR(0x89, 0x07, struct timespec)
#define SIOCGSTAMPNS (sizeof(time_t) == sizeof(__kernel_long_t) ? \
SIOCGSTAMPNS_OLD : SIOCGSTAMPNS_TIME64)
This will define the constant to the traditional value for all
existing libc implementations as well as new libc built without
__USE_TIME_BITS64, but will use a newly defined value on
new glibc with __USE_TIME_BITS64. If anyone tries to use the
constant without first having included <time.h>, it will cause a
compile-time error, which is probably the best we can do here
(better than using an incorrect value).
There are other cases where we actually need to check
_TIME_BITS, e.g.
#if defined(__KERNEL__) || \
(defined(_TIME_BITS) && (_TIME_BITS > __BITS_PER_LONG))
struct input_timeval {
__u32 tv_sec; /* __u32 overflows in y2106 */
__s32 tv_usec;
};
#else
#define input_timeval timeval
#endif
struct input_event {
struct input_timeval time;
__u16 type;
__u16 code;
__s32 value;
};
#undef input_timeval
Here, we cannot change the binary layout of input_event as
the kernel has no idea what kind of user space is running, but
we have to prevent a new user space from using the definition
based on an incompatible 'struct timeval'. In this case, it is safe
to assume that either _TIME_BITS has been defined (on a new
libc after including time.h to see 'struct timeval'), or that we are
on an old libc with the traditional definition of timeval.
Again, this is broken in a rare corner case: user space that
assumes that input_event->time is a struct timeval, but this
will cause a compile failure for incompatible types that I see
now way around.
Both of the examples above will break silently when using an
old version of the kernel header with _TIME_BITS=64.
I would suggest to not allow building support for 64-bit time_t
on a glibc with old kernel headers because of this, but I don't
know how hard that is to do in glibc. It is probably safe to
assume that kernel headers that define
__NR_CLOCK_GETTIME64 in asm/unistd.h have a reasonable
set of definitions in their other headers as well.
For run-time dependencies, glibc can try to support old kernels
with new builds, but this support will not cover any interfaces
that are not wrapped by glibc. With the above example fo
SIOCGSTAMPNS, an application calling this ioctl on an
old kernel will run into an error with errno=EINVAL. This can
be mitigated by emulating a reasonable subset of the affected
ioctl/fcntl/sockopts/etc calls in glibc, but it would be hard to
guarantee that this works for every kernel subsystem and
device driver.
The other interesting runtime case is a kernel that
intentionally drops 32-bit time_t support in combination
with an application that uses the _TIME_BITS=32
compatibility interfaces. In this case, we want any
syscalls to fail rather than be emulated through the 64-bit
calls. This should be the normal behavior with the
implementation you describe, but I think it should be
documented that this is intentional.
Arnd