From e03c7188c72dd78d7141cf88f24dd2a5fd14c4f1 Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Fri, 6 Dec 2019 15:39:31 +0100 Subject: [PATCH] y2038: Support for Y2038 safe time on 32 bit systems The time_t type is now Y2038 safe, which means that it is aliased to __time64_t when __USE_TIME_BITS64 is defined or __time_t otherwise. On the contrary the __time_t for 32 bit systems is only 32 bit, so for Y2038 safe system it must be 64 bit (as is time_t) This patch introduces the Y2038 specific code to make clock_settime/ __clock_settime64 Y2038 safe on 32 bit systems. This goal is achieved by using aliasing to clock_settime names when __USE_TIME_BITS64 is defined. As a result user programs call 64 bit versions of functions (i.e. __clock_settime64 instead of __clock_settime), which must have been globally visible for this purpose - for non Y2038 safe code those are hidden in glibc. Additionally this patch also converts following syscalls to be Y2038: - clock_gettime64 - clock_settime64 - clock_getres64 - utimensat - futimens - clock_nanosleep_time64 - ppoll64 - timer_gettime - timer_settime - timerfd_gettime (WIP) - timerfd_settime (WIP) - sched_rr_get_interval (WIP) - timespec_get (WIP) - settimeofday (WIP) --- Changes for vX: - Adjust the code to the current master branch of glibc - Add support for converting clock_getres to be Y2038 safe - Extend struct timeval to be Y2038 safe Changes for v3: - Only support clock_settime conversion to be Y2038 (use it as an example conversion code) Changes for v2: - Introduce unnamed padding in the struct timespec exported by glibc (to the /usr/include) --- include/features.h | 19 ++++++++++ include/sys/poll.h | 3 +- include/time.h | 24 ++++++++----- io/Versions | 1 + io/sys/poll.h | 11 ++++++ io/sys/stat.h | 20 +++++++++++ manual/creature.texi | 28 +++++++++++++++ rt/Versions | 4 +++ time/Versions | 10 ++++++ time/bits/types/struct_timespec.h | 17 +++++---- time/bits/types/struct_timeval.h | 4 +++ time/bits/types/time_t.h | 4 +++ time/time.h | 60 +++++++++++++++++++++++++++++++ 13 files changed, 190 insertions(+), 15 deletions(-) diff --git a/include/features.h b/include/features.h index af371842bb9..caec795f609 100644 --- a/include/features.h +++ b/include/features.h @@ -380,6 +380,25 @@ # define __USE_FILE_OFFSET64 1 #endif +/* We need to know the word size in order to check the time size. */ +#include + +#if defined _TIME_BITS +# if _TIME_BITS == 64 +# if ! defined (_FILE_OFFSET_BITS) || _FILE_OFFSET_BITS != 64 +# error _TIME_BITS==64 is allowed only when _FILE_OFFSET_BITS==64 +# elif __WORDSIZE == 32 +# define __USE_TIME_BITS64 1 +# endif +# elif _TIME_BITS == 32 +# if __WORDSIZE > 32 +# error _TIME_BITS=32 is not compatible with __WORDSIZE > 32 +# endif +# else +# error Invalid _TIME_BITS value (can only be 32 or 64) +# endif +#endif + #if defined _DEFAULT_SOURCE # define __USE_MISC 1 #endif diff --git a/include/sys/poll.h b/include/sys/poll.h index f904e21f89a..d977a646134 100644 --- a/include/sys/poll.h +++ b/include/sys/poll.h @@ -16,7 +16,8 @@ libc_hidden_proto (ppoll) extern int __ppoll64 (struct pollfd *fds, nfds_t nfds, const struct __timespec64 *timeout, const sigset_t *sigmask); -libc_hidden_proto (__ppoll64) +/* For Y2038 safe system the __ppoll64 needs to be a visible + symbol as a replacement for Y2038 unsafe ppoll. */ # endif #endif #endif diff --git a/include/time.h b/include/time.h index b76ffea225f..01e2ce9657c 100644 --- a/include/time.h +++ b/include/time.h @@ -164,7 +164,8 @@ libc_hidden_proto (__timegm64) #else extern int __clock_settime64 (clockid_t clock_id, const struct __timespec64 *tp); -libc_hidden_proto (__clock_settime64) +/* For Y2038 safe system the __clock_settime64 needs to be a visible + symbol as a replacement for Y2038 unsafe clock_settime. */ #endif #if __TIMESIZE == 64 @@ -172,7 +173,8 @@ libc_hidden_proto (__clock_settime64) #else extern int __clock_getres64 (clockid_t clock_id, struct __timespec64 *tp); -libc_hidden_proto (__clock_getres64); +/* For Y2038 safe system the __clock_settime64 needs to be a visible + symbol as a replacement for Y2038 unsafe clock_settime. */ #endif #if __TIMESIZE == 64 @@ -180,7 +182,8 @@ libc_hidden_proto (__clock_getres64); #else extern int __utimensat64 (int fd, const char *file, const struct __timespec64 tsp[2], int flags); -libc_hidden_proto (__utimensat64); +/* For Y2038 safe system the __utimensat64 needs to be a visible + symbol as a replacement for Y2038 unsafe utimensat. */ #endif extern int __utimensat64_helper (int fd, const char *file, @@ -191,7 +194,8 @@ libc_hidden_proto (__utimensat64_helper); # define __futimens64 __futimens #else extern int __futimens64 (int fd, const struct __timespec64 tsp[2]); -libc_hidden_proto (__futimens64); +/* For Y2038 safe system the __utimensat64 needs to be a visible + symbol as a replacement for Y2038 unsafe utimensat. */ #endif #if __TIMESIZE == 64 @@ -200,7 +204,8 @@ libc_hidden_proto (__futimens64); #else extern int __timer_gettime64 (timer_t timerid, struct __itimerspec64 *value); extern int __timerfd_gettime64 (int fd, struct __itimerspec64 *value); -libc_hidden_proto (__timer_gettime64); +/* For Y2038 safe system the __timer_gettime64 needs to be a visible + symbol as a replacement for Y2038 unsafe timer_gettime. */ libc_hidden_proto (__timerfd_gettime64); #endif @@ -211,10 +216,11 @@ libc_hidden_proto (__timerfd_gettime64); extern int __timer_settime64 (timer_t timerid, int flags, const struct __itimerspec64 *value, struct __itimerspec64 *ovalue); +/* For Y2038 safe system the __timer_settime64 needs to be a visible + symbol as a replacement for Y2038 unsafe timer_settime. */ extern int __timerfd_settime64 (int fd, int flags, const struct __itimerspec64 *value, struct __itimerspec64 *ovalue); -libc_hidden_proto (__timer_settime64); libc_hidden_proto (__timerfd_settime64); #endif @@ -282,9 +288,11 @@ extern double __difftime (time_t time1, time_t time0); extern int __clock_nanosleep_time64 (clockid_t clock_id, int flags, const struct __timespec64 *req, struct __timespec64 *rem); -libc_hidden_proto (__clock_nanosleep_time64) extern int __clock_gettime64 (clockid_t clock_id, struct __timespec64 *tp); -libc_hidden_proto (__clock_gettime64) +/* For Y2038 safe system the __clock_nanosleep_time64 needs to be a visible + symbol as a replacement for Y2038 unsafe clock_nanosleep. */ +/* For Y2038 safe system the __clock_gettime64 needs to be a visible + symbol as a replacement for Y2038 unsafe clock_gettime64. */ extern int __timespec_get64 (struct __timespec64 *ts, int base); libc_hidden_proto (__timespec_get64) #endif diff --git a/io/Versions b/io/Versions index f7e5dbe49e0..89a6c1b4e6c 100644 --- a/io/Versions +++ b/io/Versions @@ -137,5 +137,6 @@ libc { __fcntl_nocancel; __open64_nocancel; __write_nocancel; + __ppoll64; } } diff --git a/io/sys/poll.h b/io/sys/poll.h index 857be0f5ac6..4a725ed18ec 100644 --- a/io/sys/poll.h +++ b/io/sys/poll.h @@ -63,6 +63,17 @@ extern int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout); extern int ppoll (struct pollfd *__fds, nfds_t __nfds, const struct timespec *__timeout, const __sigset_t *__ss); + +# ifdef __USE_TIME_BITS64 +# if defined(__REDIRECT) +extern int __REDIRECT (ppoll, (struct pollfd *__fds, nfds_t __nfds, + const struct timespec *__timeout, + const __sigset_t *__ss), + __ppoll64); +# else +# define ppoll __ppoll64 +# endif +# endif #endif __END_DECLS diff --git a/io/sys/stat.h b/io/sys/stat.h index ce014d03a58..29426e37931 100644 --- a/io/sys/stat.h +++ b/io/sys/stat.h @@ -361,11 +361,31 @@ extern int utimensat (int __fd, const char *__path, const struct timespec __times[2], int __flags) __THROW __nonnull ((2)); + +# ifdef __USE_TIME_BITS64 +# if defined(__REDIRECT_NTH) +extern int __REDIRECT_NTH (utimensat, (int fd, const char *__path, + const struct timespec __times[2], + int flags), + __utimensat64) __nonnull ((2)); +# else +# define utimensat __utimensat64 +# endif +# endif #endif #ifdef __USE_XOPEN2K8 /* Set file access and modification times of the file associated with FD. */ extern int futimens (int __fd, const struct timespec __times[2]) __THROW; + +# ifdef __USE_TIME_BITS64 +# if defined(__REDIRECT_NTH) +extern int __REDIRECT_NTH (futimens, (int fd, const struct timespec __times[2]), + __futimens64); +# else +# define futimens __futimens64 +# endif +# endif #endif /* To allow the `struct stat' structure and the file type `mode_t' diff --git a/manual/creature.texi b/manual/creature.texi index be5050468b2..5389fb0f345 100644 --- a/manual/creature.texi +++ b/manual/creature.texi @@ -165,6 +165,34 @@ This macro was introduced as part of the Large File Support extension (LFS). @end defvr +@defvr Macro _TIME_BITS +This macro determines the bit size of @code{time_t} (and therefore the +bit size of all @code{time_t} derived types and the prototypes of all +related functions). If @code{_TIME_BITS} is undefined, the bit size of +time_t equals the bit size of the architecture. + +If @code{_TIME_BITS} is undefined, or if @code{_TIME_BITS} is defined +to the value @code{32} and @code{__WORDSIZE} is defined to the value +@code{32}, or or if @code{_TIME_BITS} is defined to the value @code{64} +and @code{__WORDSIZE} is defined to the value @code{64}, nothing changes. + +If @code{_TIME_BITS} is defined to the value @code{64} and if +@code{__WORDSIZE} is defined to the value @code{32}, then the @w{64 bit} +time API and implementation are used even though the architecture word +size is @code{32}. Also, if the kernel provides @w{64 bit} time support, +it is used; otherwise, the @w{32 bit} kernel time support is used (with +no provision to address kernel Y2038 shortcomings). + +If @code{_TIME_BITS} is defined to the value @code{32} and if +@code{__WORDSIZE} is defined to the value @code{64}, then a compile-time +error is emitted. + +If @code{_TIME_BITS} is defined to a value different from both @code{32} +and @code{64}, then a compile-time error is emitted. + +This macro was introduced as part of the Y2038 support. +@end defvr + @defvr Macro _ISOC99_SOURCE @standards{GNU, (none)} If this macro is defined, features from ISO C99 are included. Since diff --git a/rt/Versions b/rt/Versions index 84d1345420d..d5dcfe70ab9 100644 --- a/rt/Versions +++ b/rt/Versions @@ -1,4 +1,8 @@ librt { + GLIBC_PRIVATE { + __timer_gettime64; + __timer_settime64; + } GLIBC_2.1 { # AIO functions. aio_cancel; aio_cancel64; aio_error; aio_error64; aio_fsync; aio_fsync64; diff --git a/time/Versions b/time/Versions index 8788e192ce3..ad8a31c44bc 100644 --- a/time/Versions +++ b/time/Versions @@ -1,4 +1,14 @@ libc { + GLIBC_PRIVATE { + __clock_gettime64; + __clock_settime64; + __clock_getres64; + __clock_nanosleep_time64; + __utimensat64; + __futimens64; + __timer_gettime64; + __timer_settime64; + } GLIBC_2.0 { # global variables __daylight; __timezone; __tzname; diff --git a/time/bits/types/struct_timespec.h b/time/bits/types/struct_timespec.h index d11c69cfd32..3e158ad899e 100644 --- a/time/bits/types/struct_timespec.h +++ b/time/bits/types/struct_timespec.h @@ -4,25 +4,30 @@ #include #include +#include /* POSIX.1b structure for a time value. This is like a `struct timeval' but has nanoseconds instead of microseconds. */ struct timespec { +# ifdef __USE_TIME_BITS64 + __time64_t tv_sec; /* Seconds. */ +# else __time_t tv_sec; /* Seconds. */ -#if __WORDSIZE == 64 \ +# endif +# if __WORDSIZE == 64 \ || (defined __SYSCALL_WORDSIZE && __SYSCALL_WORDSIZE == 64) \ - || __TIMESIZE == 32 + || (__TIMESIZE == 32 && !defined __USE_TIME_BITS64) __syscall_slong_t tv_nsec; /* Nanoseconds. */ -#else -# if __BYTE_ORDER == __BIG_ENDIAN +# else +# if __BYTE_ORDER == __BIG_ENDIAN int: 32; /* Padding. */ long int tv_nsec; /* Nanoseconds. */ -# else +# else long int tv_nsec; /* Nanoseconds. */ int: 32; /* Padding. */ +# endif # endif -#endif }; #endif diff --git a/time/bits/types/struct_timeval.h b/time/bits/types/struct_timeval.h index 70394ce886d..9927abf5094 100644 --- a/time/bits/types/struct_timeval.h +++ b/time/bits/types/struct_timeval.h @@ -7,7 +7,11 @@ microsecond but also has a range of years. */ struct timeval { +# ifdef __USE_TIME_BITS64 + __time64_t tv_sec; /* Seconds. */ +# else __time_t tv_sec; /* Seconds. */ +# endif __suseconds_t tv_usec; /* Microseconds. */ }; #endif diff --git a/time/bits/types/time_t.h b/time/bits/types/time_t.h index ab8287c6fe5..84d67f6ac34 100644 --- a/time/bits/types/time_t.h +++ b/time/bits/types/time_t.h @@ -4,6 +4,10 @@ #include /* Returned by `time'. */ +#ifdef __USE_TIME_BITS64 +typedef __time64_t time_t; +#else typedef __time_t time_t; +#endif #endif diff --git a/time/time.h b/time/time.h index 015bc1c7f3b..bebf9fed148 100644 --- a/time/time.h +++ b/time/time.h @@ -209,13 +209,41 @@ extern int nanosleep (const struct timespec *__requested_time, /* Get resolution of clock CLOCK_ID. */ extern int clock_getres (clockid_t __clock_id, struct timespec *__res) __THROW; +#ifdef __USE_TIME_BITS64 +# if defined(__REDIRECT_NTH) +extern int __REDIRECT_NTH (clock_getres, (clockid_t __clock_id, + struct timespec *__res), + __clock_getres64); +# else +# define clock_getres __clock_getres64 +# endif +#endif + /* Get current value of clock CLOCK_ID and store it in TP. */ extern int clock_gettime (clockid_t __clock_id, struct timespec *__tp) __THROW; +#ifdef __USE_TIME_BITS64 +# if defined(__REDIRECT_NTH) +extern int __REDIRECT_NTH (clock_gettime, (clockid_t __clock_id, struct + timespec *__tp), __clock_gettime64); +# else +# define clock_gettime __clock_gettime64 +# endif +#endif + /* Set clock CLOCK_ID to value TP. */ extern int clock_settime (clockid_t __clock_id, const struct timespec *__tp) __THROW; +#ifdef __USE_TIME_BITS64 +# if defined(__REDIRECT_NTH) +extern int __REDIRECT_NTH (clock_settime, (clockid_t __clock_id, const struct + timespec *__tp), __clock_settime64); +# else +# define clock_settime __clock_settime64 +# endif +#endif + # ifdef __USE_XOPEN2K /* High-resolution sleep with the specified clock. @@ -225,6 +253,17 @@ extern int clock_nanosleep (clockid_t __clock_id, int __flags, const struct timespec *__req, struct timespec *__rem); +#ifdef __USE_TIME_BITS64 +# if defined(__REDIRECT_NTH) +extern int __REDIRECT_NTH (clock_nanosleep, (clockid_t __clock_id, int __flags, + const struct timespec *__req, + struct timespec *__rem), + __clock_nanosleep_time64); +# else +# define clock_nanosleep __clock_nanosleep_time64 +# endif +#endif + /* Return clock ID for CPU-time clock. */ extern int clock_getcpuclockid (pid_t __pid, clockid_t *__clock_id) __THROW; # endif @@ -243,10 +282,31 @@ extern int timer_settime (timer_t __timerid, int __flags, const struct itimerspec *__restrict __value, struct itimerspec *__restrict __ovalue) __THROW; +#ifdef __USE_TIME_BITS64 +# if defined(__REDIRECT_NTH) +extern int __REDIRECT_NTH (timer_settime, (timer_t __timerid, int __flags, + const struct itimerspec *__restrict __value, + struct itimerspec *__restrict __ovalue), + __timer_settime64); +# else +# define timer_settime __timer_settime64 +# endif +#endif + /* Get current value of timer TIMERID and store it in VALUE. */ extern int timer_gettime (timer_t __timerid, struct itimerspec *__value) __THROW; +#ifdef __USE_TIME_BITS64 +# if defined(__REDIRECT_NTH) +extern int __REDIRECT_NTH (timer_gettime, (timer_t __timerid, + struct itimerspec *__value), + __timer_gettime64) __nonnull ((1)); +# else +# define timer_gettime __timer_gettime64 +# endif +#endif + /* Get expiration overrun for timer TIMERID. */ extern int timer_getoverrun (timer_t __timerid) __THROW; #endif