Skip to content

Commit

Permalink
y2038: Support for Y2038 safe time on 32 bit systems
Browse files Browse the repository at this point in the history
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)
  • Loading branch information
Lukasz Majewski committed Jan 18, 2020
1 parent 2328b06 commit e03c718
Show file tree
Hide file tree
Showing 13 changed files with 190 additions and 15 deletions.
19 changes: 19 additions & 0 deletions include/features.h
Expand Up @@ -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 <bits/wordsize.h>

#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
Expand Down
3 changes: 2 additions & 1 deletion include/sys/poll.h
Expand Up @@ -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
24 changes: 16 additions & 8 deletions include/time.h
Expand Up @@ -164,23 +164,26 @@ 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
# define __clock_getres64 __clock_getres
#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
# define __utimensat64 __utimensat
#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,
Expand All @@ -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
Expand All @@ -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

Expand All @@ -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

Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions io/Versions
Expand Up @@ -137,5 +137,6 @@ libc {
__fcntl_nocancel;
__open64_nocancel;
__write_nocancel;
__ppoll64;
}
}
11 changes: 11 additions & 0 deletions io/sys/poll.h
Expand Up @@ -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
Expand Down
20 changes: 20 additions & 0 deletions io/sys/stat.h
Expand Up @@ -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'
Expand Down
28 changes: 28 additions & 0 deletions manual/creature.texi
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions 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;
Expand Down
10 changes: 10 additions & 0 deletions 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;
Expand Down
17 changes: 11 additions & 6 deletions time/bits/types/struct_timespec.h
Expand Up @@ -4,25 +4,30 @@

#include <bits/types.h>
#include <bits/endian.h>
#include <bits/types/time_t.h>

/* 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
4 changes: 4 additions & 0 deletions time/bits/types/struct_timeval.h
Expand Up @@ -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
4 changes: 4 additions & 0 deletions time/bits/types/time_t.h
Expand Up @@ -4,6 +4,10 @@
#include <bits/types.h>

/* Returned by `time'. */
#ifdef __USE_TIME_BITS64
typedef __time64_t time_t;
#else
typedef __time_t time_t;
#endif

#endif
60 changes: 60 additions & 0 deletions time/time.h
Expand Up @@ -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.
Expand All @@ -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
Expand All @@ -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
Expand Down

0 comments on commit e03c718

Please sign in to comment.