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:
- difftime
- mktime
- timegm
- ctime_r
- ctime
- gmtime_r
- gmtime
- clock_gettime64
- clock_settime64
- clock_getres64
- utimensat
- futimens
- clock_nanosleep_time64
- ppoll64
- timer_gettime
- timer_settime
- difftime
- timerfd_gettime
- timerfd_settime
- sched_rr_get_interval
- timespec_get
- settimeofday
- gettimeofday
- setitimer
- getitimer
- getrusage
- wait4_time64
- utimes
- utime
- mq_timedsend
- mq_timedreceive
- futimes
- lutimes
- futimesat
- semtimedop -> credits: Adhemerval Zanella
- pselect   -> credits: Adhemerval Zanella
- recvmmsg   -> credits: Adhemerval Zanella
- nanosleep  -> credits: Adhemerval Zanella
- select     -> credits: Adhemerval Zanella
- sigtimedwait -> credits: Adhemerval Zanella

- stat -> credits: Adhemerval Zanella
- fstat -> credits: Adhemerval Zanella
- lstat -> credits: Adhemerval Zanella
- fstatat -> credits: Adhemerval Zanella

- clock_adjtime64
- adjtime
- adjtimex
- ntp_gettime
- ntp_gettimex
- ntp_adjtime - just alias to ___adjtimex64 function

- wait3 -> credits: Adhemerval Zanella

- nptl (uses futex_time64):
        - pthread_timedjoin_np
        - pthread_clockjoin_np
        - pthread_cond_clockwait
        - pthread_cond_timedwait
        - sem_clockwait
        - sem_timedwait
        - pthread_rwlock_clockrdlock
        - pthread_rwlock_clockwrlock
        - pthread_rwlock_timedrdlock
        - pthread_rwlock_timedwrlock
        - pthread_mutex_clocklock
        - pthread_mutex_timedlock

- C11 threads
        - mtx_timedlock
        - cnd_timedwait
        - thrd_sleep

- time

Structures converted/exported:
-----------------------------
- struct timespec
- struct itimerspec
- struct timeval
- struct rusage
- WIP/RFC: export of struct stat{64}

TO DO:
------

- aio_suspend ()
- cnd_timedwait ()
- Make exportable struct __stat64_t64 and __rusage64 (to be usable when we
  redirect glibc syscalls symbols)
- utmp{x} and login in general - patches from Adhemerval Zanella waiting for
  review
- Provide Y2038 support for struct msqid_ds (and msgctl() syscall in general
- Provide Y2038 support for struct semid_ds
- Port tests from y2038-tests repository to glibc -master branch
  • Loading branch information
Lukasz Majewski committed Nov 11, 2020
1 parent 77c16f6 commit b5d9a08
Show file tree
Hide file tree
Showing 37 changed files with 811 additions and 9 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
2 changes: 2 additions & 0 deletions io/Versions
Expand Up @@ -146,5 +146,7 @@ libc {
__file_change_detection_for_path;
__file_change_detection_for_fp;
__fstat64;
__ppoll64;
__utime64;
}
}
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

#ifdef __USE_GNU
Expand Down
15 changes: 15 additions & 0 deletions io/utime.h
Expand Up @@ -35,8 +35,13 @@ __BEGIN_DECLS
/* Structure describing file times. */
struct utimbuf
{
# ifdef __USE_TIME_BITS64
__time64_t actime; /* Access time. */
__time64_t modtime; /* Modification time. */
# else
__time_t actime; /* Access time. */
__time_t modtime; /* Modification time. */
# endif
};

/* Set the access and modification times of FILE to those given in
Expand All @@ -45,6 +50,16 @@ extern int utime (const char *__file,
const struct utimbuf *__file_times)
__THROW __nonnull ((1));

#ifdef __USE_TIME_BITS64
# if defined(__REDIRECT_NTH)
extern int __REDIRECT_NTH (utime, (const char *__file,
const struct utimbuf *__file_times),
__utime64);
# else
# define utime __utime64
# endif
#endif

__END_DECLS

#endif /* utime.h */
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
5 changes: 5 additions & 0 deletions misc/Versions
Expand Up @@ -172,5 +172,10 @@ libc {
__mmap; __munmap; __mprotect;
__sched_get_priority_min; __sched_get_priority_max;
__libc_allocate_once_slow;
__utimes64;
__futimes64;
__lutimes64;
__futimesat64;
__select64;
}
}
27 changes: 27 additions & 0 deletions misc/sys/select.h
Expand Up @@ -103,6 +103,19 @@ extern int select (int __nfds, fd_set *__restrict __readfds,
fd_set *__restrict __exceptfds,
struct timeval *__restrict __timeout);

#ifdef __USE_TIME_BITS64
# if defined(__REDIRECT)
extern int __REDIRECT (select,
(int __nfds, fd_set *__restrict __readfds,
fd_set *__restrict __writefds,
fd_set *__restrict __exceptfds,
struct timeval *__restrict __timeout),
__select64);
# else
# define select __select64
# endif
#endif

#ifdef __USE_XOPEN2K
/* Same as above only that the TIMEOUT value is given with higher
resolution and a sigmask which is been set temporarily. This version
Expand All @@ -115,6 +128,20 @@ extern int pselect (int __nfds, fd_set *__restrict __readfds,
fd_set *__restrict __exceptfds,
const struct timespec *__restrict __timeout,
const __sigset_t *__restrict __sigmask);

# ifdef __USE_TIME_BITS64
# if defined(__REDIRECT)
extern int __REDIRECT (pselect,
(int __nfds, fd_set *__restrict __readfds,
fd_set *__restrict __writefds,
fd_set *__restrict __exceptfds,
const struct timespec *__restrict __timeout,
const __sigset_t *__restrict __sigmask),
__pselect64);
# else
# define pselect __pselect64
# endif
# endif
#endif


Expand Down
12 changes: 12 additions & 0 deletions nptl/Versions
Expand Up @@ -304,5 +304,17 @@ libpthread {
__pthread_barrier_init; __pthread_barrier_wait;
__shm_directory;
__libpthread_freeres;
__pthread_timedjoin_np64;
__pthread_clockjoin_np64;
__pthread_cond_timedwait64;
__pthread_cond_clockwait64;
__sem_clockwait64;
__sem_timedwait64;
__pthread_rwlock_clockrdlock64;
__pthread_rwlock_clockwrlock64;
__pthread_rwlock_timedrdlock64;
__pthread_rwlock_timedwrlock64;
__pthread_mutex_timedlock64;
__pthread_mutex_clocklock64;
}
}
2 changes: 2 additions & 0 deletions posix/Versions
Expand Up @@ -150,5 +150,7 @@ libc {
GLIBC_PRIVATE {
__libc_fork; __libc_pread; __libc_pwrite;
__nanosleep_nocancel; __pause_nocancel;
__wait4_time64; __pselect64;
__nanosleep64; __wait3_time64;
}
}
9 changes: 9 additions & 0 deletions posix/sched.h
Expand Up @@ -76,6 +76,15 @@ extern int sched_get_priority_min (int __algorithm) __THROW;
/* Get the SCHED_RR interval for the named process. */
extern int sched_rr_get_interval (__pid_t __pid, struct timespec *__t) __THROW;

#ifdef __USE_TIME_BITS64
# if defined(__REDIRECT_NTH)
extern int __REDIRECT_NTH (sched_rr_get_interval,
(__pid_t __pid, struct timespec *__t),
__sched_rr_get_interval64);
# else
# define sched_rr_get_interval __sched_rr_get_interval64
# endif
#endif

#ifdef __USE_GNU
/* Access macros for `cpu_set'. */
Expand Down
20 changes: 20 additions & 0 deletions posix/sys/wait.h
Expand Up @@ -146,12 +146,32 @@ struct rusage;
otherwise don't. */
extern __pid_t wait3 (int *__stat_loc, int __options,
struct rusage * __usage) __THROWNL;

# ifdef __USE_TIME_BITS64
# if defined(__REDIRECT_NTHNL)
extern __pid_t __REDIRECT_NTHNL (wait3, (int *__stat_loc, int __options,
struct rusage * __usage)
__wait3_time64);
# else
# define wait3 __wait3_time64
# endif
# endif
#endif

#ifdef __USE_MISC
/* PID is like waitpid. Other args are like wait3. */
extern __pid_t wait4 (__pid_t __pid, int *__stat_loc, int __options,
struct rusage *__usage) __THROWNL;

# ifdef __USE_TIME_BITS64
# if defined(__REDIRECT_NTHNL)
extern __pid_t __REDIRECT_NTHNL (wait4, (__pid_t __pid, int *__stat_loc,
int __options, struct rusage *__usage),
__wait4_time64);
# else
# define wait4 __wait4_time64
# endif
# endif
#endif /* Use misc. */


Expand Down
1 change: 1 addition & 0 deletions resource/Versions
Expand Up @@ -24,5 +24,6 @@ libc {
}
GLIBC_PRIVATE {
__getrlimit;
__getrusage64;
}
}
5 changes: 5 additions & 0 deletions resource/bits/types/struct_rusage.h
Expand Up @@ -32,10 +32,15 @@
for little-endian ones, like x32. */
struct rusage
{
#ifdef __USE_TIME_BITS64
struct __timeval64 ru_utime;
struct __timeval64 ru_stime;
#else
/* Total amount of user time used. */
struct timeval ru_utime;
/* Total amount of system time used. */
struct timeval ru_stime;
#endif
/* Maximum resident set size (in kilobytes). */
__extension__ union
{
Expand Down
10 changes: 10 additions & 0 deletions resource/sys/resource.h
Expand Up @@ -86,6 +86,16 @@ extern int setrlimit64 (__rlimit_resource_t __resource,
and put it in *USAGE. Returns 0 for success, -1 for failure. */
extern int getrusage (__rusage_who_t __who, struct rusage *__usage) __THROW;

#ifdef __USE_TIME_BITS64
# if defined(__REDIRECT_NTH)
extern int __REDIRECT_NTH (getrusage, (__rusage_who_t __who,
struct rusage *__usage),
__getrusage64);
# else
# define getrusage __getrusage64
# endif
#endif

/* Return the highest priority of any process specified by WHICH and WHO
(see above); if WHO is zero, the current process, process group, or user
(as specified by WHO) is used. A lower priority number means higher
Expand Down
6 changes: 6 additions & 0 deletions rt/Versions
@@ -1,4 +1,10 @@
librt {
GLIBC_PRIVATE {
__timer_gettime64;
__timer_settime64;
__mq_timedsend_time64;
__mq_timedreceive_time64;
}
GLIBC_2.1 {
# AIO functions.
aio_cancel; aio_cancel64; aio_error; aio_error64; aio_fsync; aio_fsync64;
Expand Down
25 changes: 25 additions & 0 deletions rt/mqueue.h
Expand Up @@ -79,12 +79,37 @@ extern ssize_t mq_timedreceive (mqd_t __mqdes, char *__restrict __msg_ptr,
const struct timespec *__restrict __abs_timeout)
__nonnull ((2, 5));

# ifdef __USE_TIME_BITS64
# if defined(__REDIRECT)
extern int __REDIRECT (mq_timedreceive, (mqd_t __mqdes,
char *__restrict __msg_ptr,
size_t __msg_len,
unsigned int *__restrict __msg_prio,
const struct timespec *__restrict __abs_timeout),
__mq_timedreceive_time64);
# else
# define mq_timedreceive __mq_timedreceive_time64
# endif
# endif

/* Add message pointed by MSG_PTR to message queue MQDES, stop blocking
on full message queue if ABS_TIMEOUT expires. */
extern int mq_timedsend (mqd_t __mqdes, const char *__msg_ptr,
size_t __msg_len, unsigned int __msg_prio,
const struct timespec *__abs_timeout)
__nonnull ((2, 5));

# ifdef __USE_TIME_BITS64
# if defined(__REDIRECT)
extern int __REDIRECT (mq_timedsend, (mqd_t __mqdes,
const char *__msg_ptr, size_t __msg_len,
unsigned int __msg_prio,
const struct timespec *__abs_timeout),
__mq_timedsend_time64);
# else
# define mq_timedsend __mq_timedsend_time64
# endif
# endif
#endif

/* Define some inlines helping to catch common problems. */
Expand Down
3 changes: 3 additions & 0 deletions signal/Versions
Expand Up @@ -51,4 +51,7 @@ libc {
}
GLIBC_2.21 {
}
GLIBC_PRIVATE {
__sigtimedwait64;
}
}
12 changes: 12 additions & 0 deletions signal/signal.h
Expand Up @@ -274,6 +274,18 @@ extern int sigtimedwait (const sigset_t *__restrict __set,
const struct timespec *__restrict __timeout)
__nonnull ((1));

# ifdef __USE_TIME_BITS64
# if defined(__REDIRECT)
extern int __REDIRECT (sigtimedwait,
(const sigset_t *__restrict __set,
siginfo_t *__restrict __info,
const struct timespec *__restrict __timeout),
__sigtimedwait64);
# else
# define sigtimedwait __sigtimedwait64
# endif
# endif

/* Send signal SIG to the process PID. Associate data in VAL with the
signal. */
extern int sigqueue (__pid_t __pid, int __sig, const union sigval __val)
Expand Down

0 comments on commit b5d9a08

Please sign in to comment.