mailing list of musl libc
 help / color / mirror / code / Atom feed
* [RFC] final time64 switch-over patch series
@ 2019-08-02 21:44 Rich Felker
  2019-08-04  4:31 ` Rich Felker
                   ` (3 more replies)
  0 siblings, 4 replies; 10+ messages in thread
From: Rich Felker @ 2019-08-02 21:44 UTC (permalink / raw)
  To: musl

[-- Attachment #1: Type: text/plain, Size: 1475 bytes --]

Final in the sense of "final steps needed", not "final version of
patch". These are very much drafts, and subject to change. The time64
commits I've already pushed added time64 syscall backends and removed
assumptions that time_t matches the type used by syscalls; the ones
attached here deal with changing over the public types in a way
compatible with existing code.

I'm looking for feedback on all of this. There are particularly a few
structs not yet adapted yet, where it's not clear what the best way to
lay them out is or how the definition should be selected (based on
_REDIR_TIME64 macro? new bits files? a separate macro controlling
struct layout? ...). There may be significant mistakes in the time32
compat shims, which would break old binaries but otherwise be
inconsequential; it wouldn't result in unfixable ABI breakage.
Analysis of possible things that might go wrong even if everything is
done right are also welcome at this point.

Schedule for going forward with this is open right now. I'm not sure
if it makes sense to quickly put out an experimental release with
this, marked as experimental in case there turn out to be ABI problems
we need to correct, or if it might be better to put out a fairly safe
release soon with the internal time64 support changes and other work,
and publish time64 switchover patches separately as something users
can try applying experimentally. Either 1.1.24 or 1.1.25 should ship
with fully 64-bit time_t, though.

Rich

[-- Attachment #2: 0001-add-time64-symbol-name-redirects-to-public-headers-u.patch --]
[-- Type: text/plain, Size: 12508 bytes --]

From 84a4c907b8ea52e11f8edb9ccc1050e31753e5ca Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias@aerifal.cx>
Date: Wed, 31 Jul 2019 15:24:58 -0400
Subject: [PATCH 1/5] add time64 symbol name redirects to public headers, under
 arch control

a _REDIR_TIME64 macro is introduced, which the arch's alltypes.h is
expected to define, to control redirection of symbol names for
interfaces that involve time_t and derived types. this ensures that
object files will only be linked to libc interfaces matching the ABI
whose headers they were compiled against.

along with time32 compat shims, which will be introduced separately,
the redirection also makes it possible for a single libc (static or
shared) to be used with object files produced with either the old
(32-bit time_t) headers or the new ones after 64-bit time_t switchover
takes place. mixing of such object files (or shared libraries) in the
same program will also be possible, but must be done with care; ABI
between libc and a consumer of the libc interfaces is guaranteed to
match by the the symbol name redirection, but pairwise ABI between
consumers of libc that define interfaces between each other in terms
of time_t is not guaranteed to match.

this change adds a dependency on an additional "GNU C" feature to the
public headers for existing 32-bit archs, which is generally
undesirable; however, the feature is one which glibc has depended on
for a long time, and thus which any viable alternative compiler is
going to need to provide. 64-bit archs are not affected, nor will
future 32-bit archs be, regardless of whether they are "new" on the
kernel side (e.g. riscv32) or just newly-added (e.g. a new sparc or
xtensa port). the same applies to newly-added ABIs for existing
machine-level archs.
---
 include/aio.h          |  4 ++++
 include/mqueue.h       |  5 +++++
 include/poll.h         |  6 ++++++
 include/pthread.h      | 10 ++++++++++
 include/sched.h        |  4 ++++
 include/semaphore.h    |  4 ++++
 include/signal.h       |  8 ++++++++
 include/sys/resource.h |  4 ++++
 include/sys/select.h   |  5 +++++
 include/sys/sem.h      |  6 ++++++
 include/sys/socket.h   |  6 ++++++
 include/sys/stat.h     |  9 +++++++++
 include/sys/time.h     | 14 ++++++++++++++
 include/sys/timeb.h    |  4 ++++
 include/sys/timerfd.h  |  5 +++++
 include/sys/timex.h    |  5 +++++
 include/sys/wait.h     |  7 +++++++
 include/threads.h      |  6 ++++++
 include/time.h         | 28 ++++++++++++++++++++++++++++
 include/utime.h        |  4 ++++
 20 files changed, 144 insertions(+)

diff --git a/include/aio.h b/include/aio.h
index 19bc28a9..482b2a70 100644
--- a/include/aio.h
+++ b/include/aio.h
@@ -62,6 +62,10 @@ int lio_listio(int, struct aiocb *__restrict const *__restrict, int, struct sige
 #define off64_t off_t
 #endif
 
+#if _REDIR_TIME64
+int aio_suspend() __asm__("__aio_suspend_time64");
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/mqueue.h b/include/mqueue.h
index f5cbe796..49525512 100644
--- a/include/mqueue.h
+++ b/include/mqueue.h
@@ -30,6 +30,11 @@ ssize_t mq_timedreceive(mqd_t, char *__restrict, size_t, unsigned *__restrict, c
 int mq_timedsend(mqd_t, const char *, size_t, unsigned, const struct timespec *);
 int mq_unlink(const char *);
 
+#if _REDIR_TIME64
+ssize_t mq_timedreceive() __asm__("__mq_timedreceive_time64");
+int mq_timedsend() __asm__("__mq_timedsend_time64");
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/poll.h b/include/poll.h
index daccc760..2aa64ab9 100644
--- a/include/poll.h
+++ b/include/poll.h
@@ -44,6 +44,12 @@ int poll (struct pollfd *, nfds_t, int);
 int ppoll(struct pollfd *, nfds_t, const struct timespec *, const sigset_t *);
 #endif
 
+#if _REDIR_TIME64
+#ifdef _GNU_SOURCE
+int ppoll() __asm__("__ppoll_time64");
+#endif
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/pthread.h b/include/pthread.h
index e238321b..252ed607 100644
--- a/include/pthread.h
+++ b/include/pthread.h
@@ -224,6 +224,16 @@ int pthread_tryjoin_np(pthread_t, void **);
 int pthread_timedjoin_np(pthread_t, void **, const struct timespec *);
 #endif
 
+#if _REDIR_TIME64
+int pthread_mutex_timedlock() __asm__("__pthread_mutex_timedlock_time64");
+int pthread_cond_timedwait() __asm__("__pthread_cond_timedwait_time64");
+int pthread_rwlock_timedrdlock() __asm__("__pthread_rwlock_timedrdlock_time64");
+int pthread_rwlock_timedwrlock() __asm__("__pthread_rwlock_timedwrlock_time64");
+#ifdef _GNU_SOURCE
+int pthread_timedjoin_np() __asm__("__pthread_timedjoin_np_time64");
+#endif
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/sched.h b/include/sched.h
index 05d40b1e..6b0e1caa 100644
--- a/include/sched.h
+++ b/include/sched.h
@@ -130,6 +130,10 @@ __CPU_op_func_S(XOR, ^)
 
 #endif
 
+#if _REDIR_TIME64
+int sched_rr_get_interval() __asm__("__sched_rr_get_interval_time64");
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/semaphore.h b/include/semaphore.h
index 277c47d6..0f9b3a32 100644
--- a/include/semaphore.h
+++ b/include/semaphore.h
@@ -29,6 +29,10 @@ int    sem_trywait(sem_t *);
 int    sem_unlink(const char *);
 int    sem_wait(sem_t *);
 
+#if _REDIR_TIME64
+int sem_timedwait() __asm__("__sem_timedwait_time64");
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/signal.h b/include/signal.h
index 5c48cb83..5697b291 100644
--- a/include/signal.h
+++ b/include/signal.h
@@ -271,6 +271,14 @@ typedef int sig_atomic_t;
 void (*signal(int, void (*)(int)))(int);
 int raise(int);
 
+#if _REDIR_TIME64
+#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
+ || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \
+ || defined(_BSD_SOURCE)
+int sigtimedwait() __asm__("__sigtimedwait_time64");
+#endif
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/sys/resource.h b/include/sys/resource.h
index 70d793d5..7f6771f2 100644
--- a/include/sys/resource.h
+++ b/include/sys/resource.h
@@ -104,6 +104,10 @@ int prlimit(pid_t, int, const struct rlimit *, struct rlimit *);
 #define rlim64_t rlim_t
 #endif
 
+#if _REDIR_TIME64
+int getrusage() __asm__("__getrusage_time64");
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/sys/select.h b/include/sys/select.h
index d34cbf10..b5de95d3 100644
--- a/include/sys/select.h
+++ b/include/sys/select.h
@@ -35,6 +35,11 @@ int pselect (int, fd_set *__restrict, fd_set *__restrict, fd_set *__restrict, co
 #define NFDBITS (8*(int)sizeof(long))
 #endif
 
+#if _REDIR_TIME64
+int select() __asm__("__select_time64");
+int pselect() __asm__("__pselect_time64");
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/sys/sem.h b/include/sys/sem.h
index 410c8774..f10bb2e8 100644
--- a/include/sys/sem.h
+++ b/include/sys/sem.h
@@ -62,6 +62,12 @@ int semop(int, struct sembuf *, size_t);
 int semtimedop(int, struct sembuf *, size_t, const struct timespec *);
 #endif
 
+#if _REDIR_TIME64
+#ifdef _GNU_SOURCE
+int semtimedop() __asm__("__semtimedop_time64");
+#endif
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/sys/socket.h b/include/sys/socket.h
index 8692efa7..7391d48c 100644
--- a/include/sys/socket.h
+++ b/include/sys/socket.h
@@ -350,6 +350,12 @@ int setsockopt (int, int, int, const void *, socklen_t);
 
 int sockatmark (int);
 
+#if _REDIR_TIME64
+#ifdef _GNU_SOURCE
+int recvmmsg() __asm__("__recvmmsg_time64");
+#endif
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/sys/stat.h b/include/sys/stat.h
index 9d096624..385faafe 100644
--- a/include/sys/stat.h
+++ b/include/sys/stat.h
@@ -110,6 +110,15 @@ int lchmod(const char *, mode_t);
 #define off64_t off_t
 #endif
 
+#if _REDIR_TIME64
+int stat() __asm__("__stat_time64");
+int fstat() __asm__("__fstat_time64");
+int lstat() __asm__("__lstat_time64");
+int fstatat() __asm__("__fstatat_time64");
+int futimens() __asm__("__futimens_time64");
+int utimensat() __asm__("__utimensat_time64");
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/sys/time.h b/include/sys/time.h
index c5cab814..d4c5d024 100644
--- a/include/sys/time.h
+++ b/include/sys/time.h
@@ -56,6 +56,20 @@ int adjtime (const struct timeval *, struct timeval *);
 	(void)0 )
 #endif
 
+#if _REDIR_TIME64
+int gettimeofday() __asm__("__gettimeofday_time64");
+int getitimer() __asm__("__getitimer_time64");
+int setitimer() __asm__("__setitimer_time64");
+int utimes() __asm__("__utimes_time64");
+#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
+int futimes() __asm__("__futimes_time64");
+int futimesat() __asm__("__futimesat_time64");
+int lutimes() __asm__("__lutimes_time64");
+int settimeofday() __asm__("__settimeofday_time64");
+int adjtime() __asm__("__adjtime64");
+#endif
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/sys/timeb.h b/include/sys/timeb.h
index 108c1f5c..8f4a01da 100644
--- a/include/sys/timeb.h
+++ b/include/sys/timeb.h
@@ -16,6 +16,10 @@ struct timeb {
 
 int ftime(struct timeb *);
 
+#if _REDIR_TIME64
+int ftime() __asm__("__ftime64");
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/sys/timerfd.h b/include/sys/timerfd.h
index 2794d36a..54b5e3a4 100644
--- a/include/sys/timerfd.h
+++ b/include/sys/timerfd.h
@@ -20,6 +20,11 @@ int timerfd_create(int, int);
 int timerfd_settime(int, int, const struct itimerspec *, struct itimerspec *);
 int timerfd_gettime(int, struct itimerspec *);
 
+#if _REDIR_TIME64
+int timerfd_settime() __asm__("__timerfd_settime64");
+int timerfd_gettime() __asm__("__timerfd_gettime64");
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/sys/timex.h b/include/sys/timex.h
index 2e688880..9a28d3ed 100644
--- a/include/sys/timex.h
+++ b/include/sys/timex.h
@@ -91,6 +91,11 @@ struct timex {
 int adjtimex(struct timex *);
 int clock_adjtime(clockid_t, struct timex *);
 
+#if _REDIR_TIME64
+int adjtimex() __asm__("__adjtimex_time64");
+int clock_adjtime() __asm__("__clock_adjtime64");
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/sys/wait.h b/include/sys/wait.h
index 50c5c709..2f40f15b 100644
--- a/include/sys/wait.h
+++ b/include/sys/wait.h
@@ -53,6 +53,13 @@ pid_t wait4 (pid_t, int *, int, struct rusage *);
 #define WIFSIGNALED(s) (((s)&0xffff)-1U < 0xffu)
 #define WIFCONTINUED(s) ((s) == 0xffff)
 
+#if _REDIR_TIME64
+#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
+pid_t wait3() __asm__("__wait3_time64");
+pid_t wait4() __asm__("__wait4_time64");
+#endif
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/threads.h b/include/threads.h
index 8122b3b1..7d683024 100644
--- a/include/threads.h
+++ b/include/threads.h
@@ -80,6 +80,12 @@ void tss_delete(tss_t);
 int tss_set(tss_t, void *);
 void *tss_get(tss_t);
 
+#if _REDIR_TIME64
+int thrd_sleep() __asm__("__thrd_sleep_time64");
+int mtx_timedlock() __asm__("__mtx_timedlock_time64");
+int cnd_timedwait() __asm__("__cnd_timedwait_time64");
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/time.h b/include/time.h
index 672b3fc3..7fd7f8c4 100644
--- a/include/time.h
+++ b/include/time.h
@@ -130,6 +130,34 @@ int stime(const time_t *);
 time_t timegm(struct tm *);
 #endif
 
+#if _REDIR_TIME64
+time_t time() __asm__("__time64");
+double difftime() __asm__("__difftime64");
+time_t mktime() __asm__("__mktime64");
+struct tm *gmtime() __asm__("__gmtime64");
+struct tm *localtime() __asm__("__localtime64");
+char *ctime() __asm__("__ctime64");
+int timespec_get() __asm__("__timespec_get_time64");
+#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
+ || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \
+ || defined(_BSD_SOURCE)
+struct tm *gmtime_r() __asm__("__gmtime64_r");
+struct tm *localtime_r() __asm__("__localtime64_r");
+char *ctime_r() __asm__("__ctime64_r");
+int nanosleep() __asm__("__nanosleep_time64");
+int clock_getres() __asm__("__clock_getres_time64");
+int clock_gettime() __asm__("__clock_gettime64");
+int clock_settime() __asm__("__clock_settime64");
+int clock_nanosleep() __asm__("__clock_nanosleep_time64");
+int timer_settime() __asm__("__timer_settime64");
+int timer_gettime() __asm__("__timer_gettime64");
+#endif
+#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
+int stime() __asm__("__stime64");
+time_t timegm() __asm__("__timegm_time64");
+#endif
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/utime.h b/include/utime.h
index dd5ff927..7fc491de 100644
--- a/include/utime.h
+++ b/include/utime.h
@@ -16,6 +16,10 @@ struct utimbuf {
 
 int utime (const char *, const struct utimbuf *);
 
+#if _REDIR_TIME64
+int utime() __asm__("__utime64");
+#endif
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.21.0


[-- Attachment #3: 0002-disable-lfs64-aliases-for-remapped-time64-functions.patch --]
[-- Type: text/plain, Size: 2763 bytes --]

From 830030b265ae3977cfec5a08ffdc231958f5dd7e Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias@aerifal.cx>
Date: Thu, 1 Aug 2019 00:56:48 -0400
Subject: [PATCH 2/5] disable lfs64 aliases for remapped time64 functions

these functions cannot provide the glibc lfs64-ABI-compatible symbols
when time_t differs from what it was in that ABI. instead, the aliases
need to be provided by the time32 compat shims or through some other
mechanism.
---
 src/aio/aio_suspend.c | 2 ++
 src/stat/__xstat.c    | 4 ++++
 src/stat/fstat.c      | 2 ++
 src/stat/fstatat.c    | 2 ++
 src/stat/lstat.c      | 2 ++
 src/stat/stat.c       | 2 ++
 6 files changed, 14 insertions(+)

diff --git a/src/aio/aio_suspend.c b/src/aio/aio_suspend.c
index 9b24b6af..34b66f87 100644
--- a/src/aio/aio_suspend.c
+++ b/src/aio/aio_suspend.c
@@ -73,4 +73,6 @@ int aio_suspend(const struct aiocb *const cbs[], int cnt, const struct timespec
 	}
 }
 
+#if !_REDIR_TIME64
 weak_alias(aio_suspend, aio_suspend64);
+#endif
diff --git a/src/stat/__xstat.c b/src/stat/__xstat.c
index f6303430..630936a0 100644
--- a/src/stat/__xstat.c
+++ b/src/stat/__xstat.c
@@ -1,5 +1,7 @@
 #include <sys/stat.h>
 
+#if !_REDIR_TIME64
+
 int __fxstat(int ver, int fd, struct stat *buf)
 {
 	return fstat(fd, buf);
@@ -25,6 +27,8 @@ weak_alias(__fxstatat, __fxstatat64);
 weak_alias(__lxstat, __lxstat64);
 weak_alias(__xstat, __xstat64);
 
+#endif
+
 int __xmknod(int ver, const char *path, mode_t mode, dev_t *dev)
 {
 	return mknod(path, mode, *dev);
diff --git a/src/stat/fstat.c b/src/stat/fstat.c
index 07f9a5de..9bbb46de 100644
--- a/src/stat/fstat.c
+++ b/src/stat/fstat.c
@@ -10,4 +10,6 @@ int fstat(int fd, struct stat *st)
 	return fstatat(fd, "", st, AT_EMPTY_PATH);
 }
 
+#if !_REDIR_TIME64
 weak_alias(fstat, fstat64);
+#endif
diff --git a/src/stat/fstatat.c b/src/stat/fstatat.c
index d915fa10..bf0a554c 100644
--- a/src/stat/fstatat.c
+++ b/src/stat/fstatat.c
@@ -126,4 +126,6 @@ int fstatat(int fd, const char *restrict path, struct stat *restrict st, int fla
 	return __syscall_ret(ret);
 }
 
+#if !_REDIR_TIME64
 weak_alias(fstatat, fstatat64);
+#endif
diff --git a/src/stat/lstat.c b/src/stat/lstat.c
index 9f95218a..6fe004de 100644
--- a/src/stat/lstat.c
+++ b/src/stat/lstat.c
@@ -6,4 +6,6 @@ int lstat(const char *restrict path, struct stat *restrict buf)
 	return fstatat(AT_FDCWD, path, buf, AT_SYMLINK_NOFOLLOW);
 }
 
+#if !_REDIR_TIME64
 weak_alias(lstat, lstat64);
+#endif
diff --git a/src/stat/stat.c b/src/stat/stat.c
index 528870d2..ea70efc4 100644
--- a/src/stat/stat.c
+++ b/src/stat/stat.c
@@ -6,4 +6,6 @@ int stat(const char *restrict path, struct stat *restrict buf)
 	return fstatat(AT_FDCWD, path, buf, 0);
 }
 
+#if !_REDIR_TIME64
 weak_alias(stat, stat64);
+#endif
-- 
2.21.0


[-- Attachment #4: 0003-make-fstatat-fill-in-old-time32-stat-fields-too.patch --]
[-- Type: text/plain, Size: 2013 bytes --]

From 05a518efb87910dcb2e7814c2c875ded75d20fee Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias@aerifal.cx>
Date: Thu, 1 Aug 2019 21:33:57 -0400
Subject: [PATCH 3/5] make fstatat fill in old time32 stat fields too

here _REDIR_TIME64 is used as an indication that there's an old ABI,
and thereby the old time32 timespec fields of struct stat.

keeping struct stat compatible and providing both versions of the
timespec fields is done so that ftw/nftw does not need painful compat
shims, and (more importantly) so that similar interfaces between pairs
of libc consumers (applications/libraries) will be less likely to
break when one has been rebuilt for time64 but the other has not.
---
 src/stat/fstatat.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/src/stat/fstatat.c b/src/stat/fstatat.c
index bf0a554c..de165b5c 100644
--- a/src/stat/fstatat.c
+++ b/src/stat/fstatat.c
@@ -57,6 +57,14 @@ static int fstatat_statx(int fd, const char *restrict path, struct stat *restric
 		.st_mtim.tv_nsec = stx.stx_mtime.tv_nsec,
 		.st_ctim.tv_sec = stx.stx_ctime.tv_sec,
 		.st_ctim.tv_nsec = stx.stx_ctime.tv_nsec,
+#if _REDIR_TIME64
+		.__st_atim32.tv_sec = stx.stx_atime.tv_sec,
+		.__st_atim32.tv_nsec = stx.stx_atime.tv_nsec,
+		.__st_mtim32.tv_sec = stx.stx_mtime.tv_sec,
+		.__st_mtim32.tv_nsec = stx.stx_mtime.tv_nsec,
+		.__st_ctim32.tv_sec = stx.stx_ctime.tv_sec,
+		.__st_ctim32.tv_nsec = stx.stx_ctime.tv_nsec,
+#endif
 	};
 	return 0;
 }
@@ -110,6 +118,14 @@ static int fstatat_kstat(int fd, const char *restrict path, struct stat *restric
 		.st_mtim.tv_nsec = kst.st_mtime_nsec,
 		.st_ctim.tv_sec = kst.st_ctime_sec,
 		.st_ctim.tv_nsec = kst.st_ctime_nsec,
+#if _REDIR_TIME64
+		.__st_atim32.tv_sec = kst.st_atime_sec,
+		.__st_atim32.tv_nsec = kst.st_atime_nsec,
+		.__st_mtim32.tv_sec = kst.st_mtime_sec,
+		.__st_mtim32.tv_nsec = kst.st_mtime_nsec,
+		.__st_ctim32.tv_sec = kst.st_ctime_sec,
+		.__st_ctim32.tv_nsec = kst.st_ctime_nsec,
+#endif
 	};
 
 	return 0;
-- 
2.21.0


[-- Attachment #5: 0004-add-time32-ABI-compat-shims-compat-source-tree.patch --]
[-- Type: text/plain, Size: 48069 bytes --]

From 58ca7e623694655aa17dbfff1206fb7c579256d5 Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias@aerifal.cx>
Date: Fri, 2 Aug 2019 15:52:42 -0400
Subject: [PATCH 4/5] add time32 ABI compat shims, compat source tree

these files provide the symbols for the traditional 32-bit time_t ABI
on existing 32-bit archs by wrapping the real, internal versions of
the corresponding functions, which always work with 64-bit time_t.
they are written to be as agnostic as possible to the implementation
details of the real functions, so that they can be written once and
mostly forgotten, but they are aware of details of the old (and
sometimes new) ABI, which is okay since ABI is fixed and cannot
change.

a new compat tree is added, separate from src, which the Makefile does
not see or use now, but which archs will be able to add to the build
process. we could also consider moving other things that are compat
shims here, like functions which are purely for glibc-ABI-compat, with
the goal of making it optional or just cleaning up the main src tree
to make the distinction between actual implementation/API files and
ABI-compat shims clear.
---
 compat/time32/__xstat.c                       | 22 +++++
 compat/time32/adjtime32.c                     | 19 ++++
 compat/time32/adjtimex_time32.c               | 37 ++++++++
 compat/time32/aio_suspend_time32.c            | 11 +++
 compat/time32/clock_adjtime32.c               | 37 ++++++++
 compat/time32/clock_getres_time32.c           | 12 +++
 compat/time32/clock_gettime32.c               | 18 ++++
 compat/time32/clock_nanosleep_time32.c        | 15 +++
 compat/time32/clock_settime32.c               |  9 ++
 compat/time32/cnd_timedwait_time32.c          |  9 ++
 compat/time32/ctime32.c                       |  7 ++
 compat/time32/ctime32_r.c                     |  7 ++
 compat/time32/difftime32.c                    |  7 ++
 compat/time32/fstat_time32.c                  | 17 ++++
 compat/time32/fstatat_time32.c                | 17 ++++
 compat/time32/ftime32.c                       | 25 +++++
 compat/time32/futimens_time32.c               | 10 ++
 compat/time32/futimes_time32.c                | 12 +++
 compat/time32/futimesat_time32.c              | 12 +++
 compat/time32/getitimer_time32.c              | 15 +++
 compat/time32/getrusage_time32.c              | 30 ++++++
 compat/time32/gettimeofday_time32.c           | 18 ++++
 compat/time32/gmtime32.c                      |  7 ++
 compat/time32/gmtime32_r.c                    |  7 ++
 compat/time32/localtime32.c                   |  7 ++
 compat/time32/localtime32_r.c                 |  7 ++
 compat/time32/lstat_time32.c                  | 17 ++++
 compat/time32/lutimes_time32.c                | 12 +++
 compat/time32/mktime32.c                      | 14 +++
 compat/time32/mq_timedreceive_time32.c        |  9 ++
 compat/time32/mq_timedsend_time32.c           |  9 ++
 compat/time32/mtx_timedlock_time32.c          |  9 ++
 compat/time32/nanosleep_time32.c              | 15 +++
 compat/time32/ppoll_time32.c                  | 10 ++
 compat/time32/pselect_time32.c                |  9 ++
 compat/time32/pthread_cond_timedwait_time32.c |  9 ++
 .../time32/pthread_mutex_timedlock_time32.c   |  9 ++
 .../pthread_rwlock_timedrdlock_time32.c       |  9 ++
 .../pthread_rwlock_timedwrlock_time32.c       |  9 ++
 compat/time32/pthread_timedjoin_np_time32.c   | 10 ++
 compat/time32/recvmmsg_time32.c               | 10 ++
 compat/time32/sched_rr_get_interval_time32.c  | 13 +++
 compat/time32/select_time32.c                 | 10 ++
 compat/time32/sem_timedwait_time32.c          |  9 ++
 compat/time32/semtimedop_time32.c             | 10 ++
 compat/time32/setitimer_time32.c              | 23 +++++
 compat/time32/settimeofday_time32.c           | 10 ++
 compat/time32/sigtimedwait_time32.c           |  9 ++
 compat/time32/stat_time32.c                   | 17 ++++
 compat/time32/stime32.c                       |  8 ++
 compat/time32/thrd_sleep_time32.c             | 16 ++++
 compat/time32/time32.c                        | 15 +++
 compat/time32/time32.h                        | 91 +++++++++++++++++++
 compat/time32/time32gm.c                      | 15 +++
 compat/time32/timer_gettime32.c               | 15 +++
 compat/time32/timer_settime32.c               | 22 +++++
 compat/time32/timerfd_gettime32.c             | 16 ++++
 compat/time32/timerfd_settime32.c             | 23 +++++
 compat/time32/timespec_get_time32.c           | 18 ++++
 compat/time32/utime_time32.c                  | 14 +++
 compat/time32/utimensat_time32.c              | 11 +++
 compat/time32/utimes_time32.c                 | 11 +++
 compat/time32/wait3_time32.c                  | 31 +++++++
 compat/time32/wait4_time32.c                  | 31 +++++++
 64 files changed, 992 insertions(+)
 create mode 100644 compat/time32/__xstat.c
 create mode 100644 compat/time32/adjtime32.c
 create mode 100644 compat/time32/adjtimex_time32.c
 create mode 100644 compat/time32/aio_suspend_time32.c
 create mode 100644 compat/time32/clock_adjtime32.c
 create mode 100644 compat/time32/clock_getres_time32.c
 create mode 100644 compat/time32/clock_gettime32.c
 create mode 100644 compat/time32/clock_nanosleep_time32.c
 create mode 100644 compat/time32/clock_settime32.c
 create mode 100644 compat/time32/cnd_timedwait_time32.c
 create mode 100644 compat/time32/ctime32.c
 create mode 100644 compat/time32/ctime32_r.c
 create mode 100644 compat/time32/difftime32.c
 create mode 100644 compat/time32/fstat_time32.c
 create mode 100644 compat/time32/fstatat_time32.c
 create mode 100644 compat/time32/ftime32.c
 create mode 100644 compat/time32/futimens_time32.c
 create mode 100644 compat/time32/futimes_time32.c
 create mode 100644 compat/time32/futimesat_time32.c
 create mode 100644 compat/time32/getitimer_time32.c
 create mode 100644 compat/time32/getrusage_time32.c
 create mode 100644 compat/time32/gettimeofday_time32.c
 create mode 100644 compat/time32/gmtime32.c
 create mode 100644 compat/time32/gmtime32_r.c
 create mode 100644 compat/time32/localtime32.c
 create mode 100644 compat/time32/localtime32_r.c
 create mode 100644 compat/time32/lstat_time32.c
 create mode 100644 compat/time32/lutimes_time32.c
 create mode 100644 compat/time32/mktime32.c
 create mode 100644 compat/time32/mq_timedreceive_time32.c
 create mode 100644 compat/time32/mq_timedsend_time32.c
 create mode 100644 compat/time32/mtx_timedlock_time32.c
 create mode 100644 compat/time32/nanosleep_time32.c
 create mode 100644 compat/time32/ppoll_time32.c
 create mode 100644 compat/time32/pselect_time32.c
 create mode 100644 compat/time32/pthread_cond_timedwait_time32.c
 create mode 100644 compat/time32/pthread_mutex_timedlock_time32.c
 create mode 100644 compat/time32/pthread_rwlock_timedrdlock_time32.c
 create mode 100644 compat/time32/pthread_rwlock_timedwrlock_time32.c
 create mode 100644 compat/time32/pthread_timedjoin_np_time32.c
 create mode 100644 compat/time32/recvmmsg_time32.c
 create mode 100644 compat/time32/sched_rr_get_interval_time32.c
 create mode 100644 compat/time32/select_time32.c
 create mode 100644 compat/time32/sem_timedwait_time32.c
 create mode 100644 compat/time32/semtimedop_time32.c
 create mode 100644 compat/time32/setitimer_time32.c
 create mode 100644 compat/time32/settimeofday_time32.c
 create mode 100644 compat/time32/sigtimedwait_time32.c
 create mode 100644 compat/time32/stat_time32.c
 create mode 100644 compat/time32/stime32.c
 create mode 100644 compat/time32/thrd_sleep_time32.c
 create mode 100644 compat/time32/time32.c
 create mode 100644 compat/time32/time32.h
 create mode 100644 compat/time32/time32gm.c
 create mode 100644 compat/time32/timer_gettime32.c
 create mode 100644 compat/time32/timer_settime32.c
 create mode 100644 compat/time32/timerfd_gettime32.c
 create mode 100644 compat/time32/timerfd_settime32.c
 create mode 100644 compat/time32/timespec_get_time32.c
 create mode 100644 compat/time32/utime_time32.c
 create mode 100644 compat/time32/utimensat_time32.c
 create mode 100644 compat/time32/utimes_time32.c
 create mode 100644 compat/time32/wait3_time32.c
 create mode 100644 compat/time32/wait4_time32.c

diff --git a/compat/time32/__xstat.c b/compat/time32/__xstat.c
new file mode 100644
index 00000000..d8cd5ef2
--- /dev/null
+++ b/compat/time32/__xstat.c
@@ -0,0 +1,22 @@
+#include "time32.h"
+#include <sys/stat.h>
+
+int __fxstat64(int ver, int fd, struct stat *buf)
+{
+	return __fstat_time32(fd, buf);
+}
+
+int __fxstatat64(int ver, int fd, const char *path, struct stat *buf, int flag)
+{
+	return __fstatat_time32(fd, path, buf, flag);
+}
+
+int __lxstat64(int ver, const char *path, struct stat *buf)
+{
+	return __lstat_time32(path, buf);
+}
+
+int __xstat64(int ver, const char *path, struct stat *buf)
+{
+	return __stat_time32(path, buf);
+}
diff --git a/compat/time32/adjtime32.c b/compat/time32/adjtime32.c
new file mode 100644
index 00000000..459be156
--- /dev/null
+++ b/compat/time32/adjtime32.c
@@ -0,0 +1,19 @@
+#define _GNU_SOURCE
+#include "time32.h"
+#include <time.h>
+#include <sys/time.h>
+#include <sys/timex.h>
+
+int __adjtime32(const struct timeval32 *in32, struct timeval32 *out32)
+{
+	struct timeval out;
+	int r = adjtime((&(struct timeval){
+		.tv_sec = in32->tv_sec,
+		.tv_usec = in32->tv_usec}), &out);
+	if (r) return r;
+	/* We can't range-check the result because success was already
+	 * committed by the above call. */
+	out32->tv_sec = out.tv_sec;
+	out32->tv_usec = out.tv_usec;
+	return r;
+}
diff --git a/compat/time32/adjtimex_time32.c b/compat/time32/adjtimex_time32.c
new file mode 100644
index 00000000..d7541da8
--- /dev/null
+++ b/compat/time32/adjtimex_time32.c
@@ -0,0 +1,37 @@
+#include "time32.h"
+#include <time.h>
+#include <sys/time.h>
+#include <sys/timex.h>
+#include <string.h>
+#include <stddef.h>
+
+struct oldtimex {
+	unsigned modes;
+	long offset, freq, maxerror, esterror;
+	int status;
+	long constant, precision, tolerance;
+	long time_sec, time_usec;
+	long tick, ppsfreq, jitter;
+	int shift;
+	long stabil, jitcnt, calcnt, errcnt, stbcnt;
+	int tai;
+	int __padding[11];
+};
+
+int __adjtimex_time32(struct timex *tx32)
+{
+	struct timex utx;
+	memcpy(&utx, tx32, sizeof(struct oldtimex));
+	utx.time.tv_sec =
+		*(long *)((char *)tx32 + offsetof(struct oldtimex,time_sec));
+	utx.time.tv_usec =
+		*(long *)((char *)tx32 + offsetof(struct oldtimex,time_usec));
+	int r = adjtimex(&utx);
+	if (r<0) return r;
+	memcpy(tx32, &utx, sizeof(struct oldtimex));
+	*(long *)((char *)tx32 + offsetof(struct oldtimex,time_sec)) =
+		utx.time.tv_sec;
+	*(long *)((char *)tx32 + offsetof(struct oldtimex,time_usec)) =
+		utx.time.tv_usec;
+	return r;
+}
diff --git a/compat/time32/aio_suspend_time32.c b/compat/time32/aio_suspend_time32.c
new file mode 100644
index 00000000..0c43ddee
--- /dev/null
+++ b/compat/time32/aio_suspend_time32.c
@@ -0,0 +1,11 @@
+#include "time32.h"
+#include <time.h>
+#include <aio.h>
+
+int __aio_suspend_time32(const struct aiocb *const cbs[], int cnt, const struct timespec32 *ts32)
+{
+	return aio_suspend(cbs, cnt, (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
+
+weak_alias(aio_suspend, aio_suspend64);
diff --git a/compat/time32/clock_adjtime32.c b/compat/time32/clock_adjtime32.c
new file mode 100644
index 00000000..36cc6053
--- /dev/null
+++ b/compat/time32/clock_adjtime32.c
@@ -0,0 +1,37 @@
+#include "time32.h"
+#include <time.h>
+#include <sys/time.h>
+#include <sys/timex.h>
+#include <string.h>
+#include <stddef.h>
+
+struct oldtimex {
+	unsigned modes;
+	long offset, freq, maxerror, esterror;
+	int status;
+	long constant, precision, tolerance;
+	long time_sec, time_usec;
+	long tick, ppsfreq, jitter;
+	int shift;
+	long stabil, jitcnt, calcnt, errcnt, stbcnt;
+	int tai;
+	int __padding[11];
+};
+
+int __clock_adjtime32(clockid_t clock_id, struct timex *tx32)
+{
+	struct timex utx;
+	memcpy(&utx, tx32, sizeof(struct oldtimex));
+	utx.time.tv_sec =
+		*(long *)((char *)tx32 + offsetof(struct oldtimex,time_sec));
+	utx.time.tv_usec =
+		*(long *)((char *)tx32 + offsetof(struct oldtimex,time_usec));
+	int r = clock_adjtime(clock_id, &utx);
+	if (r<0) return r;
+	memcpy(tx32, &utx, sizeof(struct oldtimex));
+	*(long *)((char *)tx32 + offsetof(struct oldtimex,time_sec)) =
+		utx.time.tv_sec;
+	*(long *)((char *)tx32 + offsetof(struct oldtimex,time_usec)) =
+		utx.time.tv_usec;
+	return r;
+}
diff --git a/compat/time32/clock_getres_time32.c b/compat/time32/clock_getres_time32.c
new file mode 100644
index 00000000..ab110b36
--- /dev/null
+++ b/compat/time32/clock_getres_time32.c
@@ -0,0 +1,12 @@
+#include "time32.h"
+#include <time.h>
+
+int __clock_getres_time32(clockid_t clk, struct timespec32 *ts32)
+{
+	struct timespec ts;
+	int r = clock_getres(clk, &ts);
+	if (r) return r;
+	ts32->tv_sec = ts.tv_sec;
+	ts32->tv_nsec = ts.tv_nsec;
+	return 0;
+}
diff --git a/compat/time32/clock_gettime32.c b/compat/time32/clock_gettime32.c
new file mode 100644
index 00000000..0cac7bbd
--- /dev/null
+++ b/compat/time32/clock_gettime32.c
@@ -0,0 +1,18 @@
+#include "time32.h"
+#include <time.h>
+#include <errno.h>
+#include <stdint.h>
+
+int __clock_gettime32(clockid_t clk, struct timespec32 *ts32)
+{
+	struct timespec ts;
+	int r = clock_gettime(clk, &ts);
+	if (r) return r;
+	if (ts.tv_sec < INT32_MIN || ts.tv_sec > INT32_MAX) {
+		errno = EOVERFLOW;
+		return -1;
+	}
+	ts32->tv_sec = ts.tv_sec;
+	ts32->tv_nsec = ts.tv_nsec;
+	return 0;
+}
diff --git a/compat/time32/clock_nanosleep_time32.c b/compat/time32/clock_nanosleep_time32.c
new file mode 100644
index 00000000..91ef067d
--- /dev/null
+++ b/compat/time32/clock_nanosleep_time32.c
@@ -0,0 +1,15 @@
+#include "time32.h"
+#include <time.h>
+#include <errno.h>
+
+int __clock_nanosleep_time32(clockid_t clk, int flags, const struct timespec32 *req32, struct timespec32 *rem32)
+{
+	struct timespec rem;
+	int ret = clock_nanosleep(clk, flags, (&(struct timespec){
+		.tv_sec = req32->tv_sec, .tv_nsec = req32->tv_nsec}), &rem);
+	if (ret==EINTR && rem32 && !(flags & TIMER_ABSTIME)) {
+		rem32->tv_sec = rem.tv_sec;
+		rem32->tv_nsec = rem.tv_nsec;
+	}
+	return ret;
+}
diff --git a/compat/time32/clock_settime32.c b/compat/time32/clock_settime32.c
new file mode 100644
index 00000000..7ca4f0e9
--- /dev/null
+++ b/compat/time32/clock_settime32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <time.h>
+
+int __clock_settime32(clockid_t clk, const struct timespec32 *ts32)
+{
+	return clock_settime(clk, (&(struct timespec){
+		.tv_sec = ts32->tv_sec,
+		.tv_nsec = ts32->tv_nsec}));
+}
diff --git a/compat/time32/cnd_timedwait_time32.c b/compat/time32/cnd_timedwait_time32.c
new file mode 100644
index 00000000..46e7e289
--- /dev/null
+++ b/compat/time32/cnd_timedwait_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <time.h>
+#include <threads.h>
+
+int __cnd_timedwait_time32(cnd_t *restrict c, mtx_t *restrict m, const struct timespec32 *restrict ts32)
+{
+	return cnd_timedwait(c, m, (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/compat/time32/ctime32.c b/compat/time32/ctime32.c
new file mode 100644
index 00000000..a057274e
--- /dev/null
+++ b/compat/time32/ctime32.c
@@ -0,0 +1,7 @@
+#include "time32.h"
+#include <time.h>
+
+char *__ctime32(time32_t *t)
+{
+	return ctime(&(time_t){*t});
+}
diff --git a/compat/time32/ctime32_r.c b/compat/time32/ctime32_r.c
new file mode 100644
index 00000000..e1ad2e28
--- /dev/null
+++ b/compat/time32/ctime32_r.c
@@ -0,0 +1,7 @@
+#include "time32.h"
+#include <time.h>
+
+char *__ctime32_r(time32_t *t, char *buf)
+{
+	return ctime_r(&(time_t){*t}, buf);
+}
diff --git a/compat/time32/difftime32.c b/compat/time32/difftime32.c
new file mode 100644
index 00000000..15c65709
--- /dev/null
+++ b/compat/time32/difftime32.c
@@ -0,0 +1,7 @@
+#include "time32.h"
+#include <time.h>
+
+double __difftime32(time32_t t1, time_t t2)
+{
+	return difftime(t1, t2);
+}
diff --git a/compat/time32/fstat_time32.c b/compat/time32/fstat_time32.c
new file mode 100644
index 00000000..3e084398
--- /dev/null
+++ b/compat/time32/fstat_time32.c
@@ -0,0 +1,17 @@
+#include "time32.h"
+#include <time.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <stddef.h>
+
+struct stat32;
+
+int __fstat_time32(int fd, struct stat32 *restrict st32)
+{
+	struct stat st;
+	int r = fstat(fd, &st);
+	if (!r) memcpy(st32, &st, offsetof(struct stat, st_atim));
+	return r;
+}
+
+weak_alias(fstat, fstat64);
diff --git a/compat/time32/fstatat_time32.c b/compat/time32/fstatat_time32.c
new file mode 100644
index 00000000..85dcb008
--- /dev/null
+++ b/compat/time32/fstatat_time32.c
@@ -0,0 +1,17 @@
+#include "time32.h"
+#include <time.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <stddef.h>
+
+struct stat32;
+
+int __fstatat_time32(int fd, const char *restrict path, struct stat32 *restrict st32, int flag)
+{
+	struct stat st;
+	int r = fstatat(fd, path, &st, flag);
+	if (!r) memcpy(st32, &st, offsetof(struct stat, st_atim));
+	return r;
+}
+
+weak_alias(fstatat, fstatat64);
diff --git a/compat/time32/ftime32.c b/compat/time32/ftime32.c
new file mode 100644
index 00000000..166a6dae
--- /dev/null
+++ b/compat/time32/ftime32.c
@@ -0,0 +1,25 @@
+#include "time32.h"
+#include <sys/timeb.h>
+#include <errno.h>
+#include <stdint.h>
+
+struct timeb32 {
+	int32_t time;
+	unsigned short millitm;
+	short timezone, dstflag;
+};
+
+int __ftime32(struct timeb32 *tp)
+{
+	struct timeb tb;
+	if (ftime(&tb) < 0) return -1;
+	if (tb.time < INT32_MIN || tb.time > INT32_MAX) {
+		errno = EOVERFLOW;
+		return -1;
+	}
+	tp->time = tb.time;
+	tp->millitm = tb.millitm;
+	tp->timezone = tb.timezone;
+	tp->dstflag = tb.dstflag;
+	return 0;
+}
diff --git a/compat/time32/futimens_time32.c b/compat/time32/futimens_time32.c
new file mode 100644
index 00000000..06fa1947
--- /dev/null
+++ b/compat/time32/futimens_time32.c
@@ -0,0 +1,10 @@
+#include "time32.h"
+#include <time.h>
+#include <sys/stat.h>
+
+int __futimens_time32(int fd, const struct timespec32 *times32)
+{
+	return futimens(fd, ((struct timespec[2]){
+		{.tv_sec = times32[0].tv_sec,.tv_nsec = times32[0].tv_nsec},
+		{.tv_sec = times32[1].tv_sec,.tv_nsec = times32[1].tv_nsec}}));
+}
diff --git a/compat/time32/futimes_time32.c b/compat/time32/futimes_time32.c
new file mode 100644
index 00000000..edee9f48
--- /dev/null
+++ b/compat/time32/futimes_time32.c
@@ -0,0 +1,12 @@
+#define _GNU_SOURCE
+#include "time32.h"
+#include <time.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+int __futimes_time32(int fd, const struct timeval32 times32[2])
+{
+	return futimes(fd, ((struct timeval[2]){
+		{.tv_sec = times32[0].tv_sec,.tv_usec = times32[0].tv_usec},
+		{.tv_sec = times32[1].tv_sec,.tv_usec = times32[1].tv_usec}}));
+}
diff --git a/compat/time32/futimesat_time32.c b/compat/time32/futimesat_time32.c
new file mode 100644
index 00000000..54d1573c
--- /dev/null
+++ b/compat/time32/futimesat_time32.c
@@ -0,0 +1,12 @@
+#define _GNU_SOURCE
+#include "time32.h"
+#include <time.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+int __futimesat_time32(int dirfd, const char *pathname, const struct timeval32 times32[2])
+{
+	return futimesat(dirfd, pathname, ((struct timeval[2]){
+		{.tv_sec = times32[0].tv_sec,.tv_usec = times32[0].tv_usec},
+		{.tv_sec = times32[1].tv_sec,.tv_usec = times32[1].tv_usec}}));
+}
diff --git a/compat/time32/getitimer_time32.c b/compat/time32/getitimer_time32.c
new file mode 100644
index 00000000..4bac4bf5
--- /dev/null
+++ b/compat/time32/getitimer_time32.c
@@ -0,0 +1,15 @@
+#include "time32.h"
+#include <time.h>
+#include <sys/time.h>
+
+int __getitimer_time32(int which, struct itimerval32 *old32)
+{
+	struct itimerval old;
+	int r = getitimer(which, &old);
+	if (r) return r;
+	old32->it_interval.tv_sec = old.it_interval.tv_sec;
+	old32->it_interval.tv_usec = old.it_interval.tv_usec;
+	old32->it_value.tv_sec = old.it_value.tv_sec;
+	old32->it_value.tv_usec = old.it_value.tv_usec;
+	return 0;
+}
diff --git a/compat/time32/getrusage_time32.c b/compat/time32/getrusage_time32.c
new file mode 100644
index 00000000..f8bd46ba
--- /dev/null
+++ b/compat/time32/getrusage_time32.c
@@ -0,0 +1,30 @@
+#include "time32.h"
+#include <string.h>
+#include <sys/resource.h>
+
+struct compat_rusage {
+	struct timeval32 ru_utime;
+	struct timeval32 ru_stime;
+	long	ru_maxrss;
+	long	ru_ixrss;
+	long	ru_idrss;
+	long	ru_isrss;
+	long	ru_minflt;
+	long	ru_majflt;
+	long	ru_nswap;
+	long	ru_inblock;
+	long	ru_oublock;
+	long	ru_msgsnd;
+	long	ru_msgrcv;
+	long	ru_nsignals;
+	long	ru_nvcsw;
+	long	ru_nivcsw;
+};
+
+int __getrusage_time32(int who, struct rusage *usage)
+{
+	struct rusage ru;
+	int r = getrusage(who, &ru);
+	if (!r) memcpy(usage, &ru, sizeof(struct compat_rusage));
+	return r;
+}
diff --git a/compat/time32/gettimeofday_time32.c b/compat/time32/gettimeofday_time32.c
new file mode 100644
index 00000000..3a39775c
--- /dev/null
+++ b/compat/time32/gettimeofday_time32.c
@@ -0,0 +1,18 @@
+#include "time32.h"
+#include <sys/time.h>
+#include <errno.h>
+#include <stdint.h>
+
+int __gettimeofday_time32(struct timeval32 *tv32, void *tz)
+{
+	struct timeval tv;
+	int r = gettimeofday(&tv, 0);
+	if (r) return r;
+	if (tv.tv_sec < INT32_MIN || tv.tv_sec > INT32_MAX) {
+		errno = EOVERFLOW;
+		return -1;
+	}
+	tv32->tv_sec = tv.tv_sec;
+	tv32->tv_usec = tv.tv_usec;
+	return 0;
+}
diff --git a/compat/time32/gmtime32.c b/compat/time32/gmtime32.c
new file mode 100644
index 00000000..963f0e05
--- /dev/null
+++ b/compat/time32/gmtime32.c
@@ -0,0 +1,7 @@
+#include "time32.h"
+#include <time.h>
+
+struct tm *__gmtime32(time32_t *t)
+{
+	return gmtime(&(time_t){*t});
+}
diff --git a/compat/time32/gmtime32_r.c b/compat/time32/gmtime32_r.c
new file mode 100644
index 00000000..7d72bfb3
--- /dev/null
+++ b/compat/time32/gmtime32_r.c
@@ -0,0 +1,7 @@
+#include "time32.h"
+#include <time.h>
+
+struct tm *__gmtime32_r(time32_t *t, struct tm *tm)
+{
+	return gmtime_r(&(time_t){*t}, tm);
+}
diff --git a/compat/time32/localtime32.c b/compat/time32/localtime32.c
new file mode 100644
index 00000000..96bc3034
--- /dev/null
+++ b/compat/time32/localtime32.c
@@ -0,0 +1,7 @@
+#include "time32.h"
+#include <time.h>
+
+struct tm *__localtime32(time32_t *t)
+{
+	return localtime(&(time_t){*t});
+}
diff --git a/compat/time32/localtime32_r.c b/compat/time32/localtime32_r.c
new file mode 100644
index 00000000..633ec829
--- /dev/null
+++ b/compat/time32/localtime32_r.c
@@ -0,0 +1,7 @@
+#include "time32.h"
+#include <time.h>
+
+struct tm *__localtime32_r(time32_t *t, struct tm *tm)
+{
+	return localtime_r(&(time_t){*t}, tm);
+}
diff --git a/compat/time32/lstat_time32.c b/compat/time32/lstat_time32.c
new file mode 100644
index 00000000..c1257a14
--- /dev/null
+++ b/compat/time32/lstat_time32.c
@@ -0,0 +1,17 @@
+#include "time32.h"
+#include <time.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <stddef.h>
+
+struct stat32;
+
+int __lstat_time32(const char *restrict path, struct stat32 *restrict st32)
+{
+	struct stat st;
+	int r = lstat(path, &st);
+	if (!r) memcpy(st32, &st, offsetof(struct stat, st_atim));
+	return r;
+}
+
+weak_alias(lstat, lstat64);
diff --git a/compat/time32/lutimes_time32.c b/compat/time32/lutimes_time32.c
new file mode 100644
index 00000000..b418a2eb
--- /dev/null
+++ b/compat/time32/lutimes_time32.c
@@ -0,0 +1,12 @@
+#define _GNU_SOURCE
+#include "time32.h"
+#include <time.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+int __lutimes_time32(const char *path, const struct timeval32 times32[2])
+{
+	return lutimes(path, ((struct timeval[2]){
+		{.tv_sec = times32[0].tv_sec,.tv_usec = times32[0].tv_usec},
+		{.tv_sec = times32[1].tv_sec,.tv_usec = times32[1].tv_usec}}));
+}
diff --git a/compat/time32/mktime32.c b/compat/time32/mktime32.c
new file mode 100644
index 00000000..aeef9890
--- /dev/null
+++ b/compat/time32/mktime32.c
@@ -0,0 +1,14 @@
+#include "time32.h"
+#include <time.h>
+#include <errno.h>
+#include <stdint.h>
+
+time32_t __mktime32(struct tm *tm)
+{
+	time_t t = mktime(tm);
+	if (t < INT32_MIN || t > INT32_MAX) {
+		errno = EOVERFLOW;
+		return -1;
+	}
+	return t;
+}
diff --git a/compat/time32/mq_timedreceive_time32.c b/compat/time32/mq_timedreceive_time32.c
new file mode 100644
index 00000000..25abe9da
--- /dev/null
+++ b/compat/time32/mq_timedreceive_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <mqueue.h>
+#include <time.h>
+
+ssize_t __mq_timedreceive_time32(mqd_t mqd, char *restrict msg, size_t len, unsigned *restrict prio, const struct timespec32 *restrict ts32)
+{
+	return mq_timedreceive(mqd, msg, len, prio, (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/compat/time32/mq_timedsend_time32.c b/compat/time32/mq_timedsend_time32.c
new file mode 100644
index 00000000..2a2fea3d
--- /dev/null
+++ b/compat/time32/mq_timedsend_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <mqueue.h>
+#include <time.h>
+
+int __mq_timedsend_time32(mqd_t mqd, const char *msg, size_t len, unsigned prio, const struct timespec32 *ts32)
+{
+	return mq_timedsend(mqd, msg, len, prio, (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/compat/time32/mtx_timedlock_time32.c b/compat/time32/mtx_timedlock_time32.c
new file mode 100644
index 00000000..7f187be8
--- /dev/null
+++ b/compat/time32/mtx_timedlock_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <time.h>
+#include <threads.h>
+
+int __mtx_timedlock_time32(mtx_t *restrict m, const struct timespec32 *restrict ts32)
+{
+	return mtx_timedlock(m, (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/compat/time32/nanosleep_time32.c b/compat/time32/nanosleep_time32.c
new file mode 100644
index 00000000..ea6bdd81
--- /dev/null
+++ b/compat/time32/nanosleep_time32.c
@@ -0,0 +1,15 @@
+#include "time32.h"
+#include <time.h>
+#include <errno.h>
+
+int __nanosleep_time32(const struct timespec32 *req32, struct timespec32 *rem32)
+{
+	struct timespec rem;
+	int ret = nanosleep((&(struct timespec){
+		.tv_sec = req32->tv_sec, .tv_nsec = req32->tv_nsec}), &rem);
+	if (ret<0 && errno==EINTR && rem32) {
+		rem32->tv_sec = rem.tv_sec;
+		rem32->tv_nsec = rem.tv_nsec;
+	}
+	return ret;
+}
diff --git a/compat/time32/ppoll_time32.c b/compat/time32/ppoll_time32.c
new file mode 100644
index 00000000..d1eef134
--- /dev/null
+++ b/compat/time32/ppoll_time32.c
@@ -0,0 +1,10 @@
+#include "time32.h"
+#define _GNU_SOURCE
+#include <time.h>
+#include <poll.h>
+
+int __ppoll_time32(struct pollfd *fds, nfds_t n, const struct timespec32 *ts32, const sigset_t *mask)
+{
+	return ppoll(fds, n, (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}), mask);
+}
diff --git a/compat/time32/pselect_time32.c b/compat/time32/pselect_time32.c
new file mode 100644
index 00000000..5b358c73
--- /dev/null
+++ b/compat/time32/pselect_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <time.h>
+#include <sys/select.h>
+
+int __pselect_time32(int n, fd_set *restrict rfds, fd_set *restrict wfds, fd_set *restrict efds, const struct timespec32 *restrict ts32, const sigset_t *restrict mask)
+{
+	return pselect(n, rfds, wfds, efds, (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}), mask);
+}
diff --git a/compat/time32/pthread_cond_timedwait_time32.c b/compat/time32/pthread_cond_timedwait_time32.c
new file mode 100644
index 00000000..4f80a362
--- /dev/null
+++ b/compat/time32/pthread_cond_timedwait_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <time.h>
+#include <pthread.h>
+
+int __pthread_cond_timedwait_time32(pthread_cond_t *restrict c, pthread_mutex_t *restrict m, const struct timespec32 *restrict ts32)
+{
+	return pthread_cond_timedwait(c, m, (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/compat/time32/pthread_mutex_timedlock_time32.c b/compat/time32/pthread_mutex_timedlock_time32.c
new file mode 100644
index 00000000..400a0120
--- /dev/null
+++ b/compat/time32/pthread_mutex_timedlock_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <time.h>
+#include <pthread.h>
+
+int __pthread_mutex_timedlock_time32(pthread_mutex_t *restrict m, const struct timespec32 *restrict ts32)
+{
+	return pthread_mutex_timedlock(m, (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/compat/time32/pthread_rwlock_timedrdlock_time32.c b/compat/time32/pthread_rwlock_timedrdlock_time32.c
new file mode 100644
index 00000000..20a8d1d0
--- /dev/null
+++ b/compat/time32/pthread_rwlock_timedrdlock_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <time.h>
+#include <pthread.h>
+
+int __pthread_rwlock_timedrdlock_time32(pthread_rwlock_t *restrict rw, const struct timespec32 *restrict ts32)
+{
+	return pthread_rwlock_timedrdlock(rw, (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/compat/time32/pthread_rwlock_timedwrlock_time32.c b/compat/time32/pthread_rwlock_timedwrlock_time32.c
new file mode 100644
index 00000000..d7c100b5
--- /dev/null
+++ b/compat/time32/pthread_rwlock_timedwrlock_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <time.h>
+#include <pthread.h>
+
+int __pthread_rwlock_timedwrlock_time32(pthread_rwlock_t *restrict rw, const struct timespec32 *restrict ts32)
+{
+	return pthread_rwlock_timedwrlock(rw, (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/compat/time32/pthread_timedjoin_np_time32.c b/compat/time32/pthread_timedjoin_np_time32.c
new file mode 100644
index 00000000..0cd84026
--- /dev/null
+++ b/compat/time32/pthread_timedjoin_np_time32.c
@@ -0,0 +1,10 @@
+#define _GNU_SOURCE
+#include "time32.h"
+#include <time.h>
+#include <pthread.h>
+
+int __pthread_timedjoin_np_time32(pthread_t t, void **res, const struct timespec *at32)
+{
+	return pthread_timedjoin_np(t, res, (&(struct timespec){
+		.tv_sec = at32->tv_sec, .tv_nsec = at32->tv_nsec}));
+}
diff --git a/compat/time32/recvmmsg_time32.c b/compat/time32/recvmmsg_time32.c
new file mode 100644
index 00000000..48db6940
--- /dev/null
+++ b/compat/time32/recvmmsg_time32.c
@@ -0,0 +1,10 @@
+#include "time32.h"
+#define _GNU_SOURCE
+#include <time.h>
+#include <sys/socket.h>
+
+int __recvmmsg_time32(int fd, struct mmsghdr *msgvec, unsigned int vlen, unsigned int flags, struct timespec32 *ts32)
+{
+	return recvmmsg(fd, msgvec, vlen, flags, (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/compat/time32/sched_rr_get_interval_time32.c b/compat/time32/sched_rr_get_interval_time32.c
new file mode 100644
index 00000000..36cbbaca
--- /dev/null
+++ b/compat/time32/sched_rr_get_interval_time32.c
@@ -0,0 +1,13 @@
+#include "time32.h"
+#include <time.h>
+#include <sched.h>
+
+int __sched_rr_get_interval_time32(pid_t pid, struct timespec32 *ts32)
+{
+	struct timespec ts;
+	int r = sched_rr_get_interval(pid, &ts);
+	if (r) return r;
+	ts32->tv_sec = ts.tv_sec;
+	ts32->tv_nsec = ts.tv_nsec;
+	return r;
+}
diff --git a/compat/time32/select_time32.c b/compat/time32/select_time32.c
new file mode 100644
index 00000000..2bd76e33
--- /dev/null
+++ b/compat/time32/select_time32.c
@@ -0,0 +1,10 @@
+#include "time32.h"
+#include <time.h>
+#include <sys/time.h>
+#include <sys/select.h>
+
+int __select_time32(int n, fd_set *restrict rfds, fd_set *restrict wfds, fd_set *restrict efds, struct timeval32 *restrict tv32)
+{
+	return select(n, rfds, wfds, efds, (&(struct timeval){
+		.tv_sec = tv32->tv_sec, .tv_usec = tv32->tv_usec}));
+}
diff --git a/compat/time32/sem_timedwait_time32.c b/compat/time32/sem_timedwait_time32.c
new file mode 100644
index 00000000..a27a41dc
--- /dev/null
+++ b/compat/time32/sem_timedwait_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <time.h>
+#include <semaphore.h>
+
+int __sem_timedwait_time32(sem_t *sem, const struct timespec32 *restrict ts32)
+{
+	return sem_timedwait(sem, (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/compat/time32/semtimedop_time32.c b/compat/time32/semtimedop_time32.c
new file mode 100644
index 00000000..cd3c5c4a
--- /dev/null
+++ b/compat/time32/semtimedop_time32.c
@@ -0,0 +1,10 @@
+#include "time32.h"
+#define _GNU_SOURCE
+#include <sys/sem.h>
+#include <time.h>
+
+int __semtimedop_time32(int id, struct sembuf *buf, size_t n, const struct timespec32 *ts32)
+{
+	return semtimedop(id, buf, n, (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/compat/time32/setitimer_time32.c b/compat/time32/setitimer_time32.c
new file mode 100644
index 00000000..4651dacb
--- /dev/null
+++ b/compat/time32/setitimer_time32.c
@@ -0,0 +1,23 @@
+#include "time32.h"
+#include <time.h>
+#include <sys/time.h>
+
+int __setitimer_time32(int which, const struct itimerval32 *restrict new32, struct itimerval32 *restrict old32)
+{
+	struct itimerval old;
+	int r = setitimer(which, (&(struct itimerval){
+		.it_interval.tv_sec = new32->it_interval.tv_sec,
+		.it_interval.tv_usec = new32->it_interval.tv_usec,
+		.it_value.tv_sec = new32->it_value.tv_sec,
+		.it_value.tv_usec = new32->it_value.tv_usec}), &old);
+	if (r) return r;
+	/* The above call has already committed to success by changing the
+	 * timer setting, so we can't fail on out-of-range old value.
+	 * Since these are relative times, values large enough to overflow
+	 * don't make sense anyway. */
+	old32->it_interval.tv_sec = old.it_interval.tv_sec;
+	old32->it_interval.tv_usec = old.it_interval.tv_usec;
+	old32->it_value.tv_sec = old.it_value.tv_sec;
+	old32->it_value.tv_usec = old.it_value.tv_usec;
+	return 0;
+}
diff --git a/compat/time32/settimeofday_time32.c b/compat/time32/settimeofday_time32.c
new file mode 100644
index 00000000..181d23a7
--- /dev/null
+++ b/compat/time32/settimeofday_time32.c
@@ -0,0 +1,10 @@
+#define _BSD_SOURCE
+#include "time32.h"
+#include <sys/time.h>
+
+int __settimeofday_time32(const struct timeval32 *tv32, const void *tz)
+{
+	return settimeofday((&(struct timeval){
+		.tv_sec = tv32->tv_sec,
+		.tv_usec = tv32->tv_usec}), 0);
+}
diff --git a/compat/time32/sigtimedwait_time32.c b/compat/time32/sigtimedwait_time32.c
new file mode 100644
index 00000000..f9a525c5
--- /dev/null
+++ b/compat/time32/sigtimedwait_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <time.h>
+#include <signal.h>
+
+int __sigtimedwait_time32(const sigset_t *restrict set, siginfo_t *restrict si, const struct timespec32 *restrict ts32)
+{
+	return sigtimedwait(set, si, (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/compat/time32/stat_time32.c b/compat/time32/stat_time32.c
new file mode 100644
index 00000000..8c6121da
--- /dev/null
+++ b/compat/time32/stat_time32.c
@@ -0,0 +1,17 @@
+#include "time32.h"
+#include <time.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <stddef.h>
+
+struct stat32;
+
+int __stat_time32(const char *restrict path, struct stat32 *restrict st32)
+{
+	struct stat st;
+	int r = stat(path, &st);
+	if (!r) memcpy(st32, &st, offsetof(struct stat, st_atim));
+	return r;
+}
+
+weak_alias(stat, stat64);
diff --git a/compat/time32/stime32.c b/compat/time32/stime32.c
new file mode 100644
index 00000000..cc76364d
--- /dev/null
+++ b/compat/time32/stime32.c
@@ -0,0 +1,8 @@
+#define _GNU_SOURCE
+#include "time32.h"
+#include <time.h>
+
+int __stime32(const time32_t *t)
+{
+	return stime(&(time_t){*t});
+}
diff --git a/compat/time32/thrd_sleep_time32.c b/compat/time32/thrd_sleep_time32.c
new file mode 100644
index 00000000..59088001
--- /dev/null
+++ b/compat/time32/thrd_sleep_time32.c
@@ -0,0 +1,16 @@
+#include "time32.h"
+#include <time.h>
+#include <threads.h>
+#include <errno.h>
+
+int __thrd_sleep_time32(const struct timespec32 *req32, struct timespec32 *rem32)
+{
+	struct timespec rem;
+	int ret = thrd_sleep((&(struct timespec){
+		.tv_sec = req32->tv_sec, .tv_nsec = req32->tv_nsec}), &rem);
+	if (ret<0 && errno==EINTR && rem32) {
+		rem32->tv_sec = rem.tv_sec;
+		rem32->tv_nsec = rem.tv_nsec;
+	}
+	return ret;
+}
diff --git a/compat/time32/time32.c b/compat/time32/time32.c
new file mode 100644
index 00000000..4b8fac1c
--- /dev/null
+++ b/compat/time32/time32.c
@@ -0,0 +1,15 @@
+#include "time32.h"
+#include <time.h>
+#include <errno.h>
+#include <stdint.h>
+
+time32_t __time32(time32_t *p)
+{
+	time_t t = time(0);
+	if (t < INT32_MIN || t > INT32_MAX) {
+		errno = EOVERFLOW;
+		return -1;
+	}
+	if (p) *p = t;
+	return t;
+}
diff --git a/compat/time32/time32.h b/compat/time32/time32.h
new file mode 100644
index 00000000..fdec17c3
--- /dev/null
+++ b/compat/time32/time32.h
@@ -0,0 +1,91 @@
+#ifndef TIME32_H
+#define TIME32_H
+
+#include <sys/types.h>
+
+typedef long time32_t;
+
+struct timeval32 {
+	long tv_sec;
+	long tv_usec;
+};
+
+struct itimerval32 {
+	struct timeval32 it_interval;
+	struct timeval32 it_value;
+};
+
+struct timespec32 {
+	long tv_sec;
+	long tv_nsec;
+};
+
+struct itimerspec32 {
+	struct timespec32 it_interval;
+	struct timespec32 it_value;
+};
+
+int __adjtime32() __asm__("adjtime");
+int __adjtimex_time32() __asm__("adjtimex");
+int __aio_suspend_time32() __asm__("aio_suspend");
+int __clock_adjtime32() __asm__("clock_adjtime");
+int __clock_getres_time32() __asm__("clock_getres");
+int __clock_gettime32() __asm__("clock_gettime");
+int __clock_nanosleep_time32() __asm__("clock_nanosleep");
+int __clock_settime32() __asm__("clock_settime");
+int __cnd_timedwait_time32() __asm__("cnd_timedwait");
+char *__ctime32() __asm__("ctime");
+char *__ctime32_r() __asm__("ctime_r");
+double __difftime32() __asm__("difftime");
+int __fstat_time32() __asm__("fstat");
+int __fstatat_time32() __asm__("fstatat");
+int __ftime32() __asm__("ftime");
+int __futimens_time32() __asm__("futimens");
+int __futimes_time32() __asm__("futimes");
+int __futimesat_time32() __asm__("futimesat");
+int __getitimer_time32() __asm__("getitimer");
+int __getrusage_time32() __asm__("getrusage");
+int __gettimeofday_time32() __asm__("gettimeofday");
+struct tm *__gmtime32() __asm__("gmtime");
+struct tm *__gmtime32_r() __asm__("gmtime_r");
+struct tm *__localtime32() __asm__("localtime");
+struct tm *__localtime32_r() __asm__("localtime_r");
+int __lstat_time32() __asm__("lstat");
+int __lutimes_time32() __asm__("lutimes");
+time32_t __mktime32() __asm__("mktime");
+ssize_t __mq_timedreceive_time32() __asm__("mq_timedreceive");
+int __mq_timedsend_time32() __asm__("mq_timedsend");
+int __mtx_timedlock_time32() __asm__("mtx_timedlock");
+int __nanosleep_time32() __asm__("nanosleep");
+int __ppoll_time32() __asm__("ppoll");
+int __pselect_time32() __asm__("pselect");
+int __pthread_cond_timedwait_time32() __asm__("pthread_cond_timedwait");
+int __pthread_mutex_timedlock_time32() __asm__("pthread_mutex_timedlock");
+int __pthread_rwlock_timedrdlock_time32() __asm__("pthread_rwlock_timedrdlock");
+int __pthread_rwlock_timedwrlock_time32() __asm__("pthread_rwlock_timedwrlock");
+int __pthread_timedjoin_np_time32() __asm__("pthread_timedjoin_np");
+int __recvmmsg_time32() __asm__("recvmmsg");
+int __sched_rr_get_interval_time32() __asm__("sched_rr_get_interval");
+int __select_time32() __asm__("select");
+int __sem_timedwait_time32() __asm__("sem_timedwait");
+int __semtimedop_time32() __asm__("semtimedop");
+int __setitimer_time32() __asm__("setitimer");
+int __settimeofday_time32() __asm__("settimeofday");
+int __sigtimedwait_time32() __asm__("sigtimedwait");
+int __stat_time32() __asm__("stat");
+int __stime32() __asm__("stime");
+int __thrd_sleep_time32() __asm__("thrd_sleep");
+time32_t __time32() __asm__("time");
+time32_t __time32gm() __asm__("timegm");
+int __timer_gettime32() __asm__("timer_gettime");
+int __timer_settime32() __asm__("timer_settime");
+int __timerfd_gettime32() __asm__("timerfd_gettime");
+int __timerfd_settime32() __asm__("timerfd_settime");
+int __timespec_get_time32() __asm__("timespec_get");
+int __utime_time32() __asm__("utime");
+int __utimensat_time32() __asm__("utimensat");
+int __utimes_time32() __asm__("utimes");
+pid_t __wait3_time32() __asm__("wait3");
+pid_t __wait4_time32() __asm__("wait4");
+
+#endif
diff --git a/compat/time32/time32gm.c b/compat/time32/time32gm.c
new file mode 100644
index 00000000..60d68fbf
--- /dev/null
+++ b/compat/time32/time32gm.c
@@ -0,0 +1,15 @@
+#define _GNU_SOURCE
+#include "time32.h"
+#include <time.h>
+#include <errno.h>
+#include <stdint.h>
+
+time32_t __time32gm(struct tm *tm)
+{
+	time_t t = timegm(tm);
+	if (t < INT32_MIN || t > INT32_MAX) {
+		errno = EOVERFLOW;
+		return -1;
+	}
+	return t;
+}
diff --git a/compat/time32/timer_gettime32.c b/compat/time32/timer_gettime32.c
new file mode 100644
index 00000000..b4184cc2
--- /dev/null
+++ b/compat/time32/timer_gettime32.c
@@ -0,0 +1,15 @@
+#include "time32.h"
+#include <time.h>
+
+int __timer_gettime32(timer_t t, struct itimerspec32 *val32)
+{
+	struct itimerspec old;
+	int r = timer_gettime(t, &old);
+	if (r) return r;
+	/* No range checking for consistency with settime */
+	val32->it_interval.tv_sec = old.it_interval.tv_sec;
+	val32->it_interval.tv_nsec = old.it_interval.tv_nsec;
+	val32->it_value.tv_sec = old.it_value.tv_sec;
+	val32->it_value.tv_nsec = old.it_value.tv_nsec;
+	return 0;
+}
diff --git a/compat/time32/timer_settime32.c b/compat/time32/timer_settime32.c
new file mode 100644
index 00000000..95d597fe
--- /dev/null
+++ b/compat/time32/timer_settime32.c
@@ -0,0 +1,22 @@
+#include "time32.h"
+#include <time.h>
+
+int __timer_settime32(timer_t t, int flags, const struct itimerspec32 *restrict val32, struct itimerspec32 *restrict old32)
+{
+	struct itimerspec old;
+	int r = timer_settime(t, flags, (&(struct itimerspec){
+		.it_interval.tv_sec = val32->it_interval.tv_sec,
+		.it_interval.tv_nsec = val32->it_interval.tv_nsec,
+		.it_value.tv_sec = val32->it_value.tv_sec,
+		.it_value.tv_nsec = val32->it_value.tv_nsec}), &old);
+	if (r) return r;
+	/* The above call has already committed to success by changing the
+	 * timer setting, so we can't fail on out-of-range old value.
+	 * Since these are relative times, values large enough to overflow
+	 * don't make sense anyway. */
+	old32->it_interval.tv_sec = old.it_interval.tv_sec;
+	old32->it_interval.tv_nsec = old.it_interval.tv_nsec;
+	old32->it_value.tv_sec = old.it_value.tv_sec;
+	old32->it_value.tv_nsec = old.it_value.tv_nsec;
+	return 0;
+}
diff --git a/compat/time32/timerfd_gettime32.c b/compat/time32/timerfd_gettime32.c
new file mode 100644
index 00000000..75e5435f
--- /dev/null
+++ b/compat/time32/timerfd_gettime32.c
@@ -0,0 +1,16 @@
+#include "time32.h"
+#include <time.h>
+#include <sys/timerfd.h>
+
+int __timerfd_gettime32(int t, struct itimerspec32 *val32)
+{
+	struct itimerspec old;
+	int r = timerfd_gettime(t, &old);
+	if (r) return r;
+	/* No range checking for consistency with settime */
+	val32->it_interval.tv_sec = old.it_interval.tv_sec;
+	val32->it_interval.tv_nsec = old.it_interval.tv_nsec;
+	val32->it_value.tv_sec = old.it_value.tv_sec;
+	val32->it_value.tv_nsec = old.it_value.tv_nsec;
+	return 0;
+}
diff --git a/compat/time32/timerfd_settime32.c b/compat/time32/timerfd_settime32.c
new file mode 100644
index 00000000..a16e2700
--- /dev/null
+++ b/compat/time32/timerfd_settime32.c
@@ -0,0 +1,23 @@
+#include "time32.h"
+#include <time.h>
+#include <sys/timerfd.h>
+
+int __timerfd_settime32(int t, int flags, const struct itimerspec32 *restrict val32, struct itimerspec32 *restrict old32)
+{
+	struct itimerspec old;
+	int r = timerfd_settime(t, flags, (&(struct itimerspec){
+		.it_interval.tv_sec = val32->it_interval.tv_sec,
+		.it_interval.tv_nsec = val32->it_interval.tv_nsec,
+		.it_value.tv_sec = val32->it_value.tv_sec,
+		.it_value.tv_nsec = val32->it_value.tv_nsec}), &old);
+	if (r) return r;
+	/* The above call has already committed to success by changing the
+	 * timer setting, so we can't fail on out-of-range old value.
+	 * Since these are relative times, values large enough to overflow
+	 * don't make sense anyway. */
+	old32->it_interval.tv_sec = old.it_interval.tv_sec;
+	old32->it_interval.tv_nsec = old.it_interval.tv_nsec;
+	old32->it_value.tv_sec = old.it_value.tv_sec;
+	old32->it_value.tv_nsec = old.it_value.tv_nsec;
+	return 0;
+}
diff --git a/compat/time32/timespec_get_time32.c b/compat/time32/timespec_get_time32.c
new file mode 100644
index 00000000..e9ca94cb
--- /dev/null
+++ b/compat/time32/timespec_get_time32.c
@@ -0,0 +1,18 @@
+#include "time32.h"
+#include <time.h>
+#include <errno.h>
+#include <stdint.h>
+
+int __timespec_get_time32(struct timespec32 *ts32, int base)
+{
+	struct timespec ts;
+	int r = timespec_get(&ts, base);
+	if (!r) return r;
+	if (ts.tv_sec < INT32_MIN || ts.tv_sec > INT32_MAX) {
+		errno = EOVERFLOW;
+		return 0;
+	}
+	ts32->tv_sec = ts.tv_sec;
+	ts32->tv_nsec = ts.tv_nsec;
+	return r;
+}
diff --git a/compat/time32/utime_time32.c b/compat/time32/utime_time32.c
new file mode 100644
index 00000000..32454ddc
--- /dev/null
+++ b/compat/time32/utime_time32.c
@@ -0,0 +1,14 @@
+#include "time32.h"
+#include <time.h>
+#include <utime.h>
+
+struct utimbuf32 {
+	time32_t actime;
+	time32_t modtime;
+};
+
+int __utime_time32(const char *path, const struct utimbuf32 *times32)
+{
+	return utime(path, (&(struct utimbuf){
+		.actime = times32->actime, .modtime = times32->modtime}));
+}
diff --git a/compat/time32/utimensat_time32.c b/compat/time32/utimensat_time32.c
new file mode 100644
index 00000000..3d8e320d
--- /dev/null
+++ b/compat/time32/utimensat_time32.c
@@ -0,0 +1,11 @@
+#include "time32.h"
+#include <time.h>
+#include <sys/stat.h>
+
+int __utimensat_time32(int fd, const char *path, const struct timespec32 times32[2], int flags)
+{
+	return utimensat(fd, path, ((struct timespec[2]){
+		{.tv_sec = times32[0].tv_sec,.tv_nsec = times32[0].tv_nsec},
+		{.tv_sec = times32[1].tv_sec,.tv_nsec = times32[1].tv_nsec}}),
+		flags);
+}
diff --git a/compat/time32/utimes_time32.c b/compat/time32/utimes_time32.c
new file mode 100644
index 00000000..94abb5e7
--- /dev/null
+++ b/compat/time32/utimes_time32.c
@@ -0,0 +1,11 @@
+#include "time32.h"
+#include <time.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+int __utimes_time32(const char *path, const struct timeval32 times32[2])
+{
+	return utimes(path, ((struct timeval[2]){
+		{.tv_sec = times32[0].tv_sec,.tv_usec = times32[0].tv_usec},
+		{.tv_sec = times32[1].tv_sec,.tv_usec = times32[1].tv_usec}}));
+}
diff --git a/compat/time32/wait3_time32.c b/compat/time32/wait3_time32.c
new file mode 100644
index 00000000..f8e63b91
--- /dev/null
+++ b/compat/time32/wait3_time32.c
@@ -0,0 +1,31 @@
+#define _BSD_SOURCE
+#include "time32.h"
+#include <string.h>
+#include <sys/wait.h>
+
+struct compat_rusage {
+	struct timeval32 ru_utime;
+	struct timeval32 ru_stime;
+	long	ru_maxrss;
+	long	ru_ixrss;
+	long	ru_idrss;
+	long	ru_isrss;
+	long	ru_minflt;
+	long	ru_majflt;
+	long	ru_nswap;
+	long	ru_inblock;
+	long	ru_oublock;
+	long	ru_msgsnd;
+	long	ru_msgrcv;
+	long	ru_nsignals;
+	long	ru_nvcsw;
+	long	ru_nivcsw;
+};
+
+pid_t __wait3_time32(int *status, int options, struct rusage *usage)
+{
+	struct rusage ru;
+	int r = wait3(status, options, &ru);
+	if (!r) memcpy(usage, &ru, sizeof(struct compat_rusage));
+	return r;
+}
diff --git a/compat/time32/wait4_time32.c b/compat/time32/wait4_time32.c
new file mode 100644
index 00000000..7fbf5397
--- /dev/null
+++ b/compat/time32/wait4_time32.c
@@ -0,0 +1,31 @@
+#define _BSD_SOURCE
+#include "time32.h"
+#include <string.h>
+#include <sys/wait.h>
+
+struct compat_rusage {
+	struct timeval32 ru_utime;
+	struct timeval32 ru_stime;
+	long	ru_maxrss;
+	long	ru_ixrss;
+	long	ru_idrss;
+	long	ru_isrss;
+	long	ru_minflt;
+	long	ru_majflt;
+	long	ru_nswap;
+	long	ru_inblock;
+	long	ru_oublock;
+	long	ru_msgsnd;
+	long	ru_msgrcv;
+	long	ru_nsignals;
+	long	ru_nvcsw;
+	long	ru_nivcsw;
+};
+
+pid_t __wait4_time32(pid_t pid, int *status, int options, struct rusage *usage)
+{
+	struct rusage ru;
+	int r = wait4(pid, status, options, &ru);
+	if (!r) memcpy(usage, &ru, sizeof(struct compat_rusage));
+	return r;
+}
-- 
2.21.0


[-- Attachment #6: 0005-RFC-POC-switch-i386-to-64-bit-time_t.patch --]
[-- Type: text/plain, Size: 7573 bytes --]

From 3c6bde03ecf2aa7dac605f0a55a1be201f3d4c5f Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias@aerifal.cx>
Date: Fri, 2 Aug 2019 15:41:27 -0400
Subject: [PATCH 5/5] [RFC] [POC] switch i386 to 64-bit time_t

this is a proof of concept for converting one 32-bit arch, i386, to
64-bit time_t. known issues:

1. the switchover of timespec padding is a hack, and needs to be done
right, but that involves making alltypes.h aware of endianness, which
probably should have been done a long time ago anyway and would get
rid of inappropriate inclusion of <endian.h> in some places.

2. the rusage, utmpx, and timex structs are not correct with regard to
ABI or functionality. they need to be fixed before this is safe to
use.

3. Makefile change should be its own thing.

there are likely a lot more problems.

before upstreaming this can even be considered, heavy review of the
new ABI that's produced is needed. once this is in use, mistakes will
be permanent. we may also need to review for interfaces where the new
type is not likely to match whatever glibc ends up adopting, and
renaming the redirected symbols for those interfaces to names that
don't overlap with what glibc intends to use, so that producing future
ABI-compat layers is less painful.
---
 Makefile                     |  5 +++--
 arch/i386/arch.mak           |  1 +
 arch/i386/bits/alltypes.h.in |  5 +++--
 arch/i386/bits/ipcstat.h     |  2 +-
 arch/i386/bits/msg.h         | 15 +++++++++------
 arch/i386/bits/sem.h         | 10 ++++++----
 arch/i386/bits/shm.h         | 16 ++++++++++------
 arch/i386/bits/stat.h        |  6 +++++-
 arch/i386/syscall_arch.h     |  4 +++-
 include/alltypes.h.in        |  2 +-
 10 files changed, 42 insertions(+), 24 deletions(-)
 create mode 100644 arch/i386/arch.mak

diff --git a/Makefile b/Makefile
index b46f8ca4..d636f5a9 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@ includedir = $(prefix)/include
 libdir = $(prefix)/lib
 syslibdir = /lib
 
-SRC_DIRS = $(addprefix $(srcdir)/,src/* crt ldso)
+SRC_DIRS = $(addprefix $(srcdir)/,src/* crt ldso $(COMPAT_SRC_DIRS))
 BASE_GLOBS = $(addsuffix /*.c,$(SRC_DIRS))
 ARCH_GLOBS = $(addsuffix /$(ARCH)/*.[csS],$(SRC_DIRS))
 BASE_SRCS = $(sort $(wildcard $(BASE_GLOBS)))
@@ -27,7 +27,7 @@ ARCH_OBJS = $(patsubst $(srcdir)/%,%.o,$(basename $(ARCH_SRCS)))
 REPLACED_OBJS = $(sort $(subst /$(ARCH)/,/,$(ARCH_OBJS)))
 ALL_OBJS = $(addprefix obj/, $(filter-out $(REPLACED_OBJS), $(sort $(BASE_OBJS) $(ARCH_OBJS))))
 
-LIBC_OBJS = $(filter obj/src/%,$(ALL_OBJS))
+LIBC_OBJS = $(filter obj/src/%,$(ALL_OBJS)) $(filter obj/compat/%,$(ALL_OBJS))
 LDSO_OBJS = $(filter obj/ldso/%,$(ALL_OBJS:%.o=%.lo))
 CRT_OBJS = $(filter obj/crt/%,$(ALL_OBJS))
 
@@ -75,6 +75,7 @@ WRAPCC_CLANG = clang
 LDSO_PATHNAME = $(syslibdir)/ld-musl-$(ARCH)$(SUBARCH).so.1
 
 -include config.mak
+-include arch/$(ARCH)/arch.mak
 
 ifeq ($(ARCH),)
 
diff --git a/arch/i386/arch.mak b/arch/i386/arch.mak
new file mode 100644
index 00000000..aa4d05ce
--- /dev/null
+++ b/arch/i386/arch.mak
@@ -0,0 +1 @@
+COMPAT_SRC_DIRS = compat/time32
diff --git a/arch/i386/bits/alltypes.h.in b/arch/i386/bits/alltypes.h.in
index 1a8432d3..8069271b 100644
--- a/arch/i386/bits/alltypes.h.in
+++ b/arch/i386/bits/alltypes.h.in
@@ -1,3 +1,4 @@
+#define _REDIR_TIME64 1
 #define _Addr int
 #define _Int64 long long
 #define _Reg int
@@ -34,8 +35,8 @@ TYPEDEF struct { __attribute__((__aligned__(8))) long long __ll; long double __l
 TYPEDEF struct { alignas(8) long long __ll; long double __ld; } max_align_t;
 #endif
 
-TYPEDEF long time_t;
-TYPEDEF long suseconds_t;
+TYPEDEF long long time_t;
+TYPEDEF long long suseconds_t;
 
 TYPEDEF struct { union { int __i[9]; volatile int __vi[9]; unsigned __s[9]; } __u; } pthread_attr_t;
 TYPEDEF struct { union { int __i[6]; volatile int __vi[6]; volatile void *volatile __p[6]; } __u; } pthread_mutex_t;
diff --git a/arch/i386/bits/ipcstat.h b/arch/i386/bits/ipcstat.h
index 0018ad1e..4f4fcb0c 100644
--- a/arch/i386/bits/ipcstat.h
+++ b/arch/i386/bits/ipcstat.h
@@ -1 +1 @@
-#define IPC_STAT 2
+#define IPC_STAT 0x102
diff --git a/arch/i386/bits/msg.h b/arch/i386/bits/msg.h
index bc8436c4..7bbbb2bf 100644
--- a/arch/i386/bits/msg.h
+++ b/arch/i386/bits/msg.h
@@ -1,15 +1,18 @@
 struct msqid_ds {
 	struct ipc_perm msg_perm;
-	time_t msg_stime;
-	int __unused1;
-	time_t msg_rtime;
-	int __unused2;
-	time_t msg_ctime;
-	int __unused3;
+	unsigned long __msg_stime_lo;
+	unsigned long __msg_stime_hi;
+	unsigned long __msg_rtime_lo;
+	unsigned long __msg_rtime_hi;
+	unsigned long __msg_ctime_lo;
+	unsigned long __msg_ctime_hi;
 	unsigned long msg_cbytes;
 	msgqnum_t msg_qnum;
 	msglen_t msg_qbytes;
 	pid_t msg_lspid;
 	pid_t msg_lrpid;
 	unsigned long __unused[2];
+	time_t msg_stime;
+	time_t msg_rtime;
+	time_t msg_ctime;
 };
diff --git a/arch/i386/bits/sem.h b/arch/i386/bits/sem.h
index e61571c1..65661542 100644
--- a/arch/i386/bits/sem.h
+++ b/arch/i386/bits/sem.h
@@ -1,11 +1,13 @@
 struct semid_ds {
 	struct ipc_perm sem_perm;
-	time_t sem_otime;
-	long __unused1;
-	time_t sem_ctime;
-	long __unused2;
+	unsigned long __sem_otime_lo;
+	unsigned long __sem_otime_hi;
+	unsigned long __sem_ctime_lo;
+	unsigned long __sem_ctime_hi;
 	unsigned short sem_nsems;
 	char __sem_nsems_pad[sizeof(long)-sizeof(short)];
 	long __unused3;
 	long __unused4;
+	time_t sem_otime;
+	time_t sem_ctime;
 };
diff --git a/arch/i386/bits/shm.h b/arch/i386/bits/shm.h
index 81b2a29a..725fb469 100644
--- a/arch/i386/bits/shm.h
+++ b/arch/i386/bits/shm.h
@@ -3,17 +3,21 @@
 struct shmid_ds {
 	struct ipc_perm shm_perm;
 	size_t shm_segsz;
-	time_t shm_atime;
-	int __unused1;
-	time_t shm_dtime;
-	int __unused2;
-	time_t shm_ctime;
-	int __unused3;
+	unsigned long __shm_atime_lo;
+	unsigned long __shm_atime_hi;
+	unsigned long __shm_dtime_lo;
+	unsigned long __shm_dtime_hi;
+	unsigned long __shm_ctime_lo;
+	unsigned long __shm_ctime_hi;
 	pid_t shm_cpid;
 	pid_t shm_lpid;
 	unsigned long shm_nattch;
 	unsigned long __pad1;
 	unsigned long __pad2;
+	unsigned long __pad3;
+	time_t shm_atime;
+	time_t shm_dtime;
+	time_t shm_ctime;
 };
 
 struct shminfo {
diff --git a/arch/i386/bits/stat.h b/arch/i386/bits/stat.h
index 22b19bbf..5d7828cf 100644
--- a/arch/i386/bits/stat.h
+++ b/arch/i386/bits/stat.h
@@ -14,8 +14,12 @@ struct stat {
 	off_t st_size;
 	blksize_t st_blksize;
 	blkcnt_t st_blocks;
+	struct {
+		long tv_sec;
+		long tv_nsec;
+	} __st_atim32, __st_mtim32, __st_ctim32;
+	ino_t st_ino;
 	struct timespec st_atim;
 	struct timespec st_mtim;
 	struct timespec st_ctim;
-	ino_t st_ino;
 };
diff --git a/arch/i386/syscall_arch.h b/arch/i386/syscall_arch.h
index 22b0b28b..69642e57 100644
--- a/arch/i386/syscall_arch.h
+++ b/arch/i386/syscall_arch.h
@@ -83,7 +83,9 @@ static inline long __syscall6(long n, long a1, long a2, long a3, long a4, long a
 }
 
 #define VDSO_USEFUL
-#define VDSO_CGT_SYM "__vdso_clock_gettime"
+#define VDSO_CGT32_SYM "__vdso_clock_gettime"
+#define VDSO_CGT32_VER "LINUX_2.6"
+#define VDSO_CGT_SYM "__vdso_clock_gettime64"
 #define VDSO_CGT_VER "LINUX_2.6"
 
 #define SYSCALL_USE_SOCKETCALL
diff --git a/include/alltypes.h.in b/include/alltypes.h.in
index 4cc879b1..b90ea7fa 100644
--- a/include/alltypes.h.in
+++ b/include/alltypes.h.in
@@ -35,7 +35,7 @@ TYPEDEF void * timer_t;
 TYPEDEF int clockid_t;
 TYPEDEF long clock_t;
 STRUCT timeval { time_t tv_sec; suseconds_t tv_usec; };
-STRUCT timespec { time_t tv_sec; long tv_nsec; };
+STRUCT timespec { time_t tv_sec; long tv_nsec; long :8*(sizeof(time_t)-sizeof(long)); };
 
 TYPEDEF int pid_t;
 TYPEDEF unsigned id_t;
-- 
2.21.0


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC] final time64 switch-over patch series
  2019-08-02 21:44 [RFC] final time64 switch-over patch series Rich Felker
@ 2019-08-04  4:31 ` Rich Felker
  2019-08-09 16:30   ` Rich Felker
  2019-08-04  4:33 ` Rich Felker
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 10+ messages in thread
From: Rich Felker @ 2019-08-04  4:31 UTC (permalink / raw)
  To: musl

On Fri, Aug 02, 2019 at 05:44:33PM -0400, Rich Felker wrote:
> >From 3c6bde03ecf2aa7dac605f0a55a1be201f3d4c5f Mon Sep 17 00:00:00 2001
> From: Rich Felker <dalias@aerifal.cx>
> Date: Fri, 2 Aug 2019 15:41:27 -0400
> Subject: [PATCH 5/5] [RFC] [POC] switch i386 to 64-bit time_t
> 
> this is a proof of concept for converting one 32-bit arch, i386, to
> 64-bit time_t. known issues:
> 
> 1. the switchover of timespec padding is a hack, and needs to be done
> right, but that involves making alltypes.h aware of endianness, which
> probably should have been done a long time ago anyway and would get
> rid of inappropriate inclusion of <endian.h> in some places.
> 
> 2. the rusage, utmpx, and timex structs are not correct with regard to
> ABI or functionality. they need to be fixed before this is safe to
> use.
> 
> 3. Makefile change should be its own thing.
> 
> there are likely a lot more problems.

Add a significant incomplete prerequisite I forgot about: dlsym. There
needs to be a redirection for dlsym, and 32-bit archs need a second
asm entry point for __dlsym_time64 which first checks the symbol name
against the list of time64 redirections and rewrites the request if
it's a match.

Rich


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC] final time64 switch-over patch series
  2019-08-02 21:44 [RFC] final time64 switch-over patch series Rich Felker
  2019-08-04  4:31 ` Rich Felker
@ 2019-08-04  4:33 ` Rich Felker
  2019-08-04 18:11   ` Rich Felker
  2019-08-09 14:48 ` Rich Felker
  2019-08-14 23:55 ` Rich Felker
  3 siblings, 1 reply; 10+ messages in thread
From: Rich Felker @ 2019-08-04  4:33 UTC (permalink / raw)
  To: musl

On Fri, Aug 02, 2019 at 05:44:33PM -0400, Rich Felker wrote:
> diff --git a/compat/time32/ppoll_time32.c b/compat/time32/ppoll_time32.c
> new file mode 100644
> index 00000000..d1eef134
> --- /dev/null
> +++ b/compat/time32/ppoll_time32.c
> @@ -0,0 +1,10 @@
> +#include "time32.h"
> +#define _GNU_SOURCE
> +#include <time.h>
> +#include <poll.h>
> +
> +int __ppoll_time32(struct pollfd *fds, nfds_t n, const struct timespec32 *ts32, const sigset_t *mask)
> +{
> +	return ppoll(fds, n, (&(struct timespec){
> +		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}), mask);
> +}
> diff --git a/compat/time32/pselect_time32.c b/compat/time32/pselect_time32.c
> new file mode 100644
> index 00000000..5b358c73
> --- /dev/null
> +++ b/compat/time32/pselect_time32.c
> @@ -0,0 +1,9 @@
> +#include "time32.h"
> +#include <time.h>
> +#include <sys/select.h>
> +
> +int __pselect_time32(int n, fd_set *restrict rfds, fd_set *restrict wfds, fd_set *restrict efds, const struct timespec32 *restrict ts32, const sigset_t *restrict mask)
> +{
> +	return pselect(n, rfds, wfds, efds, (&(struct timespec){
> +		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}), mask);
> +}
> diff --git a/compat/time32/select_time32.c b/compat/time32/select_time32.c
> new file mode 100644
> index 00000000..2bd76e33
> --- /dev/null
> +++ b/compat/time32/select_time32.c
> @@ -0,0 +1,10 @@
> +#include "time32.h"
> +#include <time.h>
> +#include <sys/time.h>
> +#include <sys/select.h>
> +
> +int __select_time32(int n, fd_set *restrict rfds, fd_set *restrict wfds, fd_set *restrict efds, struct timeval32 *restrict tv32)
> +{
> +	return select(n, rfds, wfds, efds, (&(struct timeval){
> +		.tv_sec = tv32->tv_sec, .tv_usec = tv32->tv_usec}));
> +}

These all fail to check the timeout argument is non-null before
accessing it; caught in testing against Adelie and Alpine i386.

There may be other functions with the same problem; need to review
them all for this.

Rich


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC] final time64 switch-over patch series
  2019-08-04  4:33 ` Rich Felker
@ 2019-08-04 18:11   ` Rich Felker
  0 siblings, 0 replies; 10+ messages in thread
From: Rich Felker @ 2019-08-04 18:11 UTC (permalink / raw)
  To: musl

[-- Attachment #1: Type: text/plain, Size: 2849 bytes --]

On Sun, Aug 04, 2019 at 12:33:16AM -0400, Rich Felker wrote:
> On Fri, Aug 02, 2019 at 05:44:33PM -0400, Rich Felker wrote:
> > diff --git a/compat/time32/ppoll_time32.c b/compat/time32/ppoll_time32.c
> > new file mode 100644
> > index 00000000..d1eef134
> > --- /dev/null
> > +++ b/compat/time32/ppoll_time32.c
> > @@ -0,0 +1,10 @@
> > +#include "time32.h"
> > +#define _GNU_SOURCE
> > +#include <time.h>
> > +#include <poll.h>
> > +
> > +int __ppoll_time32(struct pollfd *fds, nfds_t n, const struct timespec32 *ts32, const sigset_t *mask)
> > +{
> > +	return ppoll(fds, n, (&(struct timespec){
> > +		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}), mask);
> > +}
> > diff --git a/compat/time32/pselect_time32.c b/compat/time32/pselect_time32.c
> > new file mode 100644
> > index 00000000..5b358c73
> > --- /dev/null
> > +++ b/compat/time32/pselect_time32.c
> > @@ -0,0 +1,9 @@
> > +#include "time32.h"
> > +#include <time.h>
> > +#include <sys/select.h>
> > +
> > +int __pselect_time32(int n, fd_set *restrict rfds, fd_set *restrict wfds, fd_set *restrict efds, const struct timespec32 *restrict ts32, const sigset_t *restrict mask)
> > +{
> > +	return pselect(n, rfds, wfds, efds, (&(struct timespec){
> > +		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}), mask);
> > +}
> > diff --git a/compat/time32/select_time32.c b/compat/time32/select_time32.c
> > new file mode 100644
> > index 00000000..2bd76e33
> > --- /dev/null
> > +++ b/compat/time32/select_time32.c
> > @@ -0,0 +1,10 @@
> > +#include "time32.h"
> > +#include <time.h>
> > +#include <sys/time.h>
> > +#include <sys/select.h>
> > +
> > +int __select_time32(int n, fd_set *restrict rfds, fd_set *restrict wfds, fd_set *restrict efds, struct timeval32 *restrict tv32)
> > +{
> > +	return select(n, rfds, wfds, efds, (&(struct timeval){
> > +		.tv_sec = tv32->tv_sec, .tv_usec = tv32->tv_usec}));
> > +}
> 
> These all fail to check the timeout argument is non-null before
> accessing it; caught in testing against Adelie and Alpine i386.
> 
> There may be other functions with the same problem; need to review
> them all for this.

Lots more. Patch attached. I also found one place (timer[fd]_settime)
where it's beneficial to avoid passing a pointer to "old" (the time64
intermediate buffer) when "old32" (the argument) is null -- this
avoids the real function having to try the time64 syscall since it
doesn't know if the result will fit in 32-bit. There may be other
places like this that would be nice to optimize too.

FWIW the mix of !ts32 ? 0 : ... and ts32 ? ... : 0 idioms is
intentional for legibility; the former is in some sense anti-idiomatic
but avoids separating the trivial case far away from the condition
where it's not immediately visible what it goes with. The latter (more
typical) was done in a few places where it fits in the line structure
better.

Rich

[-- Attachment #2: compat_time32_fixes_1.diff --]
[-- Type: text/plain, Size: 18044 bytes --]

diff --git a/compat/time32/adjtime32.c b/compat/time32/adjtime32.c
index 459be156..b0042c63 100644
--- a/compat/time32/adjtime32.c
+++ b/compat/time32/adjtime32.c
@@ -13,7 +13,9 @@ int __adjtime32(const struct timeval32 *in32, struct timeval32 *out32)
 	if (r) return r;
 	/* We can't range-check the result because success was already
 	 * committed by the above call. */
-	out32->tv_sec = out.tv_sec;
-	out32->tv_usec = out.tv_usec;
+	if (out32) {
+		out32->tv_sec = out.tv_sec;
+		out32->tv_usec = out.tv_usec;
+	}
 	return r;
 }
diff --git a/compat/time32/aio_suspend_time32.c b/compat/time32/aio_suspend_time32.c
index 0c43ddee..ed5119bd 100644
--- a/compat/time32/aio_suspend_time32.c
+++ b/compat/time32/aio_suspend_time32.c
@@ -4,8 +4,8 @@
 
 int __aio_suspend_time32(const struct aiocb *const cbs[], int cnt, const struct timespec32 *ts32)
 {
-	return aio_suspend(cbs, cnt, (&(struct timespec){
-		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+	return aio_suspend(cbs, cnt, ts32 ? (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}) : 0);
 }
 
 weak_alias(aio_suspend, aio_suspend64);
diff --git a/compat/time32/cnd_timedwait_time32.c b/compat/time32/cnd_timedwait_time32.c
index 46e7e289..314251d1 100644
--- a/compat/time32/cnd_timedwait_time32.c
+++ b/compat/time32/cnd_timedwait_time32.c
@@ -4,6 +4,6 @@
 
 int __cnd_timedwait_time32(cnd_t *restrict c, mtx_t *restrict m, const struct timespec32 *restrict ts32)
 {
-	return cnd_timedwait(c, m, (&(struct timespec){
-		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+	return cnd_timedwait(c, m, ts32 ? (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}) : 0);
 }
diff --git a/compat/time32/futimens_time32.c b/compat/time32/futimens_time32.c
index 06fa1947..7856f176 100644
--- a/compat/time32/futimens_time32.c
+++ b/compat/time32/futimens_time32.c
@@ -4,7 +4,7 @@
 
 int __futimens_time32(int fd, const struct timespec32 *times32)
 {
-	return futimens(fd, ((struct timespec[2]){
+	return futimens(fd, !times32 ? 0 : ((struct timespec[2]){
 		{.tv_sec = times32[0].tv_sec,.tv_nsec = times32[0].tv_nsec},
 		{.tv_sec = times32[1].tv_sec,.tv_nsec = times32[1].tv_nsec}}));
 }
diff --git a/compat/time32/futimes_time32.c b/compat/time32/futimes_time32.c
index edee9f48..f29533f1 100644
--- a/compat/time32/futimes_time32.c
+++ b/compat/time32/futimes_time32.c
@@ -6,7 +6,7 @@
 
 int __futimes_time32(int fd, const struct timeval32 times32[2])
 {
-	return futimes(fd, ((struct timeval[2]){
+	return futimes(fd, !times32 ? 0 : ((struct timeval[2]){
 		{.tv_sec = times32[0].tv_sec,.tv_usec = times32[0].tv_usec},
 		{.tv_sec = times32[1].tv_sec,.tv_usec = times32[1].tv_usec}}));
 }
diff --git a/compat/time32/futimesat_time32.c b/compat/time32/futimesat_time32.c
index 54d1573c..5a1295bd 100644
--- a/compat/time32/futimesat_time32.c
+++ b/compat/time32/futimesat_time32.c
@@ -6,7 +6,7 @@
 
 int __futimesat_time32(int dirfd, const char *pathname, const struct timeval32 times32[2])
 {
-	return futimesat(dirfd, pathname, ((struct timeval[2]){
+	return futimesat(dirfd, pathname, !times32 ? 0 : ((struct timeval[2]){
 		{.tv_sec = times32[0].tv_sec,.tv_usec = times32[0].tv_usec},
 		{.tv_sec = times32[1].tv_sec,.tv_usec = times32[1].tv_usec}}));
 }
diff --git a/compat/time32/gettimeofday_time32.c b/compat/time32/gettimeofday_time32.c
index 3a39775c..1f3ce68e 100644
--- a/compat/time32/gettimeofday_time32.c
+++ b/compat/time32/gettimeofday_time32.c
@@ -6,6 +6,7 @@
 int __gettimeofday_time32(struct timeval32 *tv32, void *tz)
 {
 	struct timeval tv;
+	if (!tv32) return 0;
 	int r = gettimeofday(&tv, 0);
 	if (r) return r;
 	if (tv.tv_sec < INT32_MIN || tv.tv_sec > INT32_MAX) {
diff --git a/compat/time32/lutimes_time32.c b/compat/time32/lutimes_time32.c
index b418a2eb..7f75cd4a 100644
--- a/compat/time32/lutimes_time32.c
+++ b/compat/time32/lutimes_time32.c
@@ -6,7 +6,7 @@
 
 int __lutimes_time32(const char *path, const struct timeval32 times32[2])
 {
-	return lutimes(path, ((struct timeval[2]){
+	return lutimes(path, !times32 ? 0 : ((struct timeval[2]){
 		{.tv_sec = times32[0].tv_sec,.tv_usec = times32[0].tv_usec},
 		{.tv_sec = times32[1].tv_sec,.tv_usec = times32[1].tv_usec}}));
 }
diff --git a/compat/time32/mq_timedreceive_time32.c b/compat/time32/mq_timedreceive_time32.c
index 25abe9da..211cea4b 100644
--- a/compat/time32/mq_timedreceive_time32.c
+++ b/compat/time32/mq_timedreceive_time32.c
@@ -4,6 +4,6 @@
 
 ssize_t __mq_timedreceive_time32(mqd_t mqd, char *restrict msg, size_t len, unsigned *restrict prio, const struct timespec32 *restrict ts32)
 {
-	return mq_timedreceive(mqd, msg, len, prio, (&(struct timespec){
-		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+	return mq_timedreceive(mqd, msg, len, prio, ts32 ? (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}) : 0);
 }
diff --git a/compat/time32/mq_timedsend_time32.c b/compat/time32/mq_timedsend_time32.c
index 2a2fea3d..93b697a7 100644
--- a/compat/time32/mq_timedsend_time32.c
+++ b/compat/time32/mq_timedsend_time32.c
@@ -4,6 +4,6 @@
 
 int __mq_timedsend_time32(mqd_t mqd, const char *msg, size_t len, unsigned prio, const struct timespec32 *ts32)
 {
-	return mq_timedsend(mqd, msg, len, prio, (&(struct timespec){
-		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+	return mq_timedsend(mqd, msg, len, prio, ts32 ? (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}) : 0);
 }
diff --git a/compat/time32/mtx_timedlock_time32.c b/compat/time32/mtx_timedlock_time32.c
index 7f187be8..a01f09b8 100644
--- a/compat/time32/mtx_timedlock_time32.c
+++ b/compat/time32/mtx_timedlock_time32.c
@@ -4,6 +4,6 @@
 
 int __mtx_timedlock_time32(mtx_t *restrict m, const struct timespec32 *restrict ts32)
 {
-	return mtx_timedlock(m, (&(struct timespec){
+	return mtx_timedlock(m, !ts32 ? 0 : (&(struct timespec){
 		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
 }
diff --git a/compat/time32/ppoll_time32.c b/compat/time32/ppoll_time32.c
index d1eef134..43b4b0df 100644
--- a/compat/time32/ppoll_time32.c
+++ b/compat/time32/ppoll_time32.c
@@ -5,6 +5,6 @@
 
 int __ppoll_time32(struct pollfd *fds, nfds_t n, const struct timespec32 *ts32, const sigset_t *mask)
 {
-	return ppoll(fds, n, (&(struct timespec){
+	return ppoll(fds, n, !ts32 ? 0 : (&(struct timespec){
 		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}), mask);
 }
diff --git a/compat/time32/pselect_time32.c b/compat/time32/pselect_time32.c
index 5b358c73..ecaa8f86 100644
--- a/compat/time32/pselect_time32.c
+++ b/compat/time32/pselect_time32.c
@@ -4,6 +4,6 @@
 
 int __pselect_time32(int n, fd_set *restrict rfds, fd_set *restrict wfds, fd_set *restrict efds, const struct timespec32 *restrict ts32, const sigset_t *restrict mask)
 {
-	return pselect(n, rfds, wfds, efds, (&(struct timespec){
+	return pselect(n, rfds, wfds, efds, !ts32 ? 0 : (&(struct timespec){
 		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}), mask);
 }
diff --git a/compat/time32/pthread_cond_timedwait_time32.c b/compat/time32/pthread_cond_timedwait_time32.c
index 4f80a362..fba1f2a9 100644
--- a/compat/time32/pthread_cond_timedwait_time32.c
+++ b/compat/time32/pthread_cond_timedwait_time32.c
@@ -4,6 +4,6 @@
 
 int __pthread_cond_timedwait_time32(pthread_cond_t *restrict c, pthread_mutex_t *restrict m, const struct timespec32 *restrict ts32)
 {
-	return pthread_cond_timedwait(c, m, (&(struct timespec){
+	return pthread_cond_timedwait(c, m, !ts32 ? 0 : (&(struct timespec){
 		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
 }
diff --git a/compat/time32/pthread_mutex_timedlock_time32.c b/compat/time32/pthread_mutex_timedlock_time32.c
index 400a0120..2d29602c 100644
--- a/compat/time32/pthread_mutex_timedlock_time32.c
+++ b/compat/time32/pthread_mutex_timedlock_time32.c
@@ -4,6 +4,6 @@
 
 int __pthread_mutex_timedlock_time32(pthread_mutex_t *restrict m, const struct timespec32 *restrict ts32)
 {
-	return pthread_mutex_timedlock(m, (&(struct timespec){
+	return pthread_mutex_timedlock(m, !ts32 ? 0 : (&(struct timespec){
 		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
 }
diff --git a/compat/time32/pthread_rwlock_timedrdlock_time32.c b/compat/time32/pthread_rwlock_timedrdlock_time32.c
index 20a8d1d0..33df27a4 100644
--- a/compat/time32/pthread_rwlock_timedrdlock_time32.c
+++ b/compat/time32/pthread_rwlock_timedrdlock_time32.c
@@ -4,6 +4,6 @@
 
 int __pthread_rwlock_timedrdlock_time32(pthread_rwlock_t *restrict rw, const struct timespec32 *restrict ts32)
 {
-	return pthread_rwlock_timedrdlock(rw, (&(struct timespec){
+	return pthread_rwlock_timedrdlock(rw, !ts32 ? 0 : (&(struct timespec){
 		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
 }
diff --git a/compat/time32/pthread_rwlock_timedwrlock_time32.c b/compat/time32/pthread_rwlock_timedwrlock_time32.c
index d7c100b5..99f24f73 100644
--- a/compat/time32/pthread_rwlock_timedwrlock_time32.c
+++ b/compat/time32/pthread_rwlock_timedwrlock_time32.c
@@ -4,6 +4,6 @@
 
 int __pthread_rwlock_timedwrlock_time32(pthread_rwlock_t *restrict rw, const struct timespec32 *restrict ts32)
 {
-	return pthread_rwlock_timedwrlock(rw, (&(struct timespec){
+	return pthread_rwlock_timedwrlock(rw, !ts32 ? 0 : (&(struct timespec){
 		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
 }
diff --git a/compat/time32/pthread_timedjoin_np_time32.c b/compat/time32/pthread_timedjoin_np_time32.c
index 0cd84026..99a26bc6 100644
--- a/compat/time32/pthread_timedjoin_np_time32.c
+++ b/compat/time32/pthread_timedjoin_np_time32.c
@@ -5,6 +5,6 @@
 
 int __pthread_timedjoin_np_time32(pthread_t t, void **res, const struct timespec *at32)
 {
-	return pthread_timedjoin_np(t, res, (&(struct timespec){
+	return pthread_timedjoin_np(t, res, !at32 ? 0 : (&(struct timespec){
 		.tv_sec = at32->tv_sec, .tv_nsec = at32->tv_nsec}));
 }
diff --git a/compat/time32/recvmmsg_time32.c b/compat/time32/recvmmsg_time32.c
index 48db6940..acf1cfb8 100644
--- a/compat/time32/recvmmsg_time32.c
+++ b/compat/time32/recvmmsg_time32.c
@@ -5,6 +5,6 @@
 
 int __recvmmsg_time32(int fd, struct mmsghdr *msgvec, unsigned int vlen, unsigned int flags, struct timespec32 *ts32)
 {
-	return recvmmsg(fd, msgvec, vlen, flags, (&(struct timespec){
-		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+	return recvmmsg(fd, msgvec, vlen, flags, ts32 ? (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}) : 0);
 }
diff --git a/compat/time32/select_time32.c b/compat/time32/select_time32.c
index 2bd76e33..2d8df9ac 100644
--- a/compat/time32/select_time32.c
+++ b/compat/time32/select_time32.c
@@ -5,6 +5,6 @@
 
 int __select_time32(int n, fd_set *restrict rfds, fd_set *restrict wfds, fd_set *restrict efds, struct timeval32 *restrict tv32)
 {
-	return select(n, rfds, wfds, efds, (&(struct timeval){
+	return select(n, rfds, wfds, efds, !tv32 ? 0 : (&(struct timeval){
 		.tv_sec = tv32->tv_sec, .tv_usec = tv32->tv_usec}));
 }
diff --git a/compat/time32/sem_timedwait_time32.c b/compat/time32/sem_timedwait_time32.c
index a27a41dc..c3469f9b 100644
--- a/compat/time32/sem_timedwait_time32.c
+++ b/compat/time32/sem_timedwait_time32.c
@@ -4,6 +4,6 @@
 
 int __sem_timedwait_time32(sem_t *sem, const struct timespec32 *restrict ts32)
 {
-	return sem_timedwait(sem, (&(struct timespec){
+	return sem_timedwait(sem, !ts32 ? 0 : (&(struct timespec){
 		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
 }
diff --git a/compat/time32/semtimedop_time32.c b/compat/time32/semtimedop_time32.c
index cd3c5c4a..34ec5281 100644
--- a/compat/time32/semtimedop_time32.c
+++ b/compat/time32/semtimedop_time32.c
@@ -5,6 +5,6 @@
 
 int __semtimedop_time32(int id, struct sembuf *buf, size_t n, const struct timespec32 *ts32)
 {
-	return semtimedop(id, buf, n, (&(struct timespec){
+	return semtimedop(id, buf, n, !ts32 ? 0 : (&(struct timespec){
 		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
 }
diff --git a/compat/time32/settimeofday_time32.c b/compat/time32/settimeofday_time32.c
index 181d23a7..09e625cb 100644
--- a/compat/time32/settimeofday_time32.c
+++ b/compat/time32/settimeofday_time32.c
@@ -4,7 +4,7 @@
 
 int __settimeofday_time32(const struct timeval32 *tv32, const void *tz)
 {
-	return settimeofday((&(struct timeval){
+	return settimeofday(!tv32 ? 0 : (&(struct timeval){
 		.tv_sec = tv32->tv_sec,
 		.tv_usec = tv32->tv_usec}), 0);
 }
diff --git a/compat/time32/sigtimedwait_time32.c b/compat/time32/sigtimedwait_time32.c
index f9a525c5..6b3aa39c 100644
--- a/compat/time32/sigtimedwait_time32.c
+++ b/compat/time32/sigtimedwait_time32.c
@@ -4,6 +4,6 @@
 
 int __sigtimedwait_time32(const sigset_t *restrict set, siginfo_t *restrict si, const struct timespec32 *restrict ts32)
 {
-	return sigtimedwait(set, si, (&(struct timespec){
+	return sigtimedwait(set, si, !ts32 ? 0 : (&(struct timespec){
 		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
 }
diff --git a/compat/time32/timer_settime32.c b/compat/time32/timer_settime32.c
index 95d597fe..a447e7d4 100644
--- a/compat/time32/timer_settime32.c
+++ b/compat/time32/timer_settime32.c
@@ -8,15 +8,18 @@ int __timer_settime32(timer_t t, int flags, const struct itimerspec32 *restrict
 		.it_interval.tv_sec = val32->it_interval.tv_sec,
 		.it_interval.tv_nsec = val32->it_interval.tv_nsec,
 		.it_value.tv_sec = val32->it_value.tv_sec,
-		.it_value.tv_nsec = val32->it_value.tv_nsec}), &old);
+		.it_value.tv_nsec = val32->it_value.tv_nsec}),
+		old32 ? &old : 0);
 	if (r) return r;
 	/* The above call has already committed to success by changing the
 	 * timer setting, so we can't fail on out-of-range old value.
 	 * Since these are relative times, values large enough to overflow
 	 * don't make sense anyway. */
-	old32->it_interval.tv_sec = old.it_interval.tv_sec;
-	old32->it_interval.tv_nsec = old.it_interval.tv_nsec;
-	old32->it_value.tv_sec = old.it_value.tv_sec;
-	old32->it_value.tv_nsec = old.it_value.tv_nsec;
+	if (old32) {
+		old32->it_interval.tv_sec = old.it_interval.tv_sec;
+		old32->it_interval.tv_nsec = old.it_interval.tv_nsec;
+		old32->it_value.tv_sec = old.it_value.tv_sec;
+		old32->it_value.tv_nsec = old.it_value.tv_nsec;
+	}
 	return 0;
 }
diff --git a/compat/time32/timerfd_settime32.c b/compat/time32/timerfd_settime32.c
index a16e2700..67830d34 100644
--- a/compat/time32/timerfd_settime32.c
+++ b/compat/time32/timerfd_settime32.c
@@ -9,15 +9,18 @@ int __timerfd_settime32(int t, int flags, const struct itimerspec32 *restrict va
 		.it_interval.tv_sec = val32->it_interval.tv_sec,
 		.it_interval.tv_nsec = val32->it_interval.tv_nsec,
 		.it_value.tv_sec = val32->it_value.tv_sec,
-		.it_value.tv_nsec = val32->it_value.tv_nsec}), &old);
+		.it_value.tv_nsec = val32->it_value.tv_nsec}),
+		old32 ? &old : 0);
 	if (r) return r;
 	/* The above call has already committed to success by changing the
 	 * timer setting, so we can't fail on out-of-range old value.
 	 * Since these are relative times, values large enough to overflow
 	 * don't make sense anyway. */
-	old32->it_interval.tv_sec = old.it_interval.tv_sec;
-	old32->it_interval.tv_nsec = old.it_interval.tv_nsec;
-	old32->it_value.tv_sec = old.it_value.tv_sec;
-	old32->it_value.tv_nsec = old.it_value.tv_nsec;
+	if (old32) {
+		old32->it_interval.tv_sec = old.it_interval.tv_sec;
+		old32->it_interval.tv_nsec = old.it_interval.tv_nsec;
+		old32->it_value.tv_sec = old.it_value.tv_sec;
+		old32->it_value.tv_nsec = old.it_value.tv_nsec;
+	}
 	return 0;
 }
diff --git a/compat/time32/utime_time32.c b/compat/time32/utime_time32.c
index 32454ddc..65f11d46 100644
--- a/compat/time32/utime_time32.c
+++ b/compat/time32/utime_time32.c
@@ -9,6 +9,6 @@ struct utimbuf32 {
 
 int __utime_time32(const char *path, const struct utimbuf32 *times32)
 {
-	return utime(path, (&(struct utimbuf){
+	return utime(path, !times32 ? 0 : (&(struct utimbuf){
 		.actime = times32->actime, .modtime = times32->modtime}));
 }
diff --git a/compat/time32/utimensat_time32.c b/compat/time32/utimensat_time32.c
index 3d8e320d..c687b8d1 100644
--- a/compat/time32/utimensat_time32.c
+++ b/compat/time32/utimensat_time32.c
@@ -4,7 +4,7 @@
 
 int __utimensat_time32(int fd, const char *path, const struct timespec32 times32[2], int flags)
 {
-	return utimensat(fd, path, ((struct timespec[2]){
+	return utimensat(fd, path, !times32 ? 0 : ((struct timespec[2]){
 		{.tv_sec = times32[0].tv_sec,.tv_nsec = times32[0].tv_nsec},
 		{.tv_sec = times32[1].tv_sec,.tv_nsec = times32[1].tv_nsec}}),
 		flags);
diff --git a/compat/time32/utimes_time32.c b/compat/time32/utimes_time32.c
index 94abb5e7..59248f62 100644
--- a/compat/time32/utimes_time32.c
+++ b/compat/time32/utimes_time32.c
@@ -5,7 +5,7 @@
 
 int __utimes_time32(const char *path, const struct timeval32 times32[2])
 {
-	return utimes(path, ((struct timeval[2]){
+	return utimes(path, !times32 ? 0 : ((struct timeval[2]){
 		{.tv_sec = times32[0].tv_sec,.tv_usec = times32[0].tv_usec},
 		{.tv_sec = times32[1].tv_sec,.tv_usec = times32[1].tv_usec}}));
 }
diff --git a/compat/time32/wait3_time32.c b/compat/time32/wait3_time32.c
index f8e63b91..0d07de4e 100644
--- a/compat/time32/wait3_time32.c
+++ b/compat/time32/wait3_time32.c
@@ -25,7 +25,7 @@ struct compat_rusage {
 pid_t __wait3_time32(int *status, int options, struct rusage *usage)
 {
 	struct rusage ru;
-	int r = wait3(status, options, &ru);
-	if (!r) memcpy(usage, &ru, sizeof(struct compat_rusage));
+	int r = wait3(status, options, usage ? &ru : 0);
+	if (!r && usage) memcpy(usage, &ru, sizeof(struct compat_rusage));
 	return r;
 }
diff --git a/compat/time32/wait4_time32.c b/compat/time32/wait4_time32.c
index 7fbf5397..f2b4e90e 100644
--- a/compat/time32/wait4_time32.c
+++ b/compat/time32/wait4_time32.c
@@ -25,7 +25,7 @@ struct compat_rusage {
 pid_t __wait4_time32(pid_t pid, int *status, int options, struct rusage *usage)
 {
 	struct rusage ru;
-	int r = wait4(pid, status, options, &ru);
-	if (!r) memcpy(usage, &ru, sizeof(struct compat_rusage));
+	int r = wait4(pid, status, options, usage ? &ru : 0);
+	if (!r && usage) memcpy(usage, &ru, sizeof(struct compat_rusage));
 	return r;
 }

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC] final time64 switch-over patch series
  2019-08-02 21:44 [RFC] final time64 switch-over patch series Rich Felker
  2019-08-04  4:31 ` Rich Felker
  2019-08-04  4:33 ` Rich Felker
@ 2019-08-09 14:48 ` Rich Felker
  2019-08-14 23:55 ` Rich Felker
  3 siblings, 0 replies; 10+ messages in thread
From: Rich Felker @ 2019-08-09 14:48 UTC (permalink / raw)
  To: musl

On Fri, Aug 02, 2019 at 05:44:33PM -0400, Rich Felker wrote:
> 2. the rusage, utmpx, and timex structs are not correct with regard to
> ABI or functionality. they need to be fixed before this is safe to
> use.

There's also struct sched_param, which contains gratuitous timespecs
for functionality we don't (and probably won't ever) support. This
will gratuitously change size when we change time_t unless action is
taken to prevent it.

My leaning here is to just remove all the sched_ss_* stuff and replace
it with same-sized reserved space. But nothing in libc accesses (read
or write) anything but a single int (sched_prio) via the sched_param
pointer, so we could just leave it and let the size change; this would
not affect any ABI between libc and the libc-consumer, but it would
affect ABI between pairs of libc-consumers using the type (which seems
pretty far-fetched. Also, we would never be able to access the
additional space it's expanded to, because the caller could plausibly
be an old binary that allocated less space. So I think just getting
rid of it all is best.

Note that we lack a proper type (what would essentially be
"__old_time_t") to define same-size replacement for the members to be
removed and replaced with "reserved" space. This is the same type we
need in rusage, timex, and possibly utmpx as well.

I could make alltypes.h define __OLD_TIME_T or something, and
conditionally use it if it's defined. But I think it may be cleaner to
use _REDIR_TIME64 as a proxy for this. If _REDIR_TIME64 is defined,
that means there's an old ABI to be matched, and "old time_t"
necessarily has type long, which is necessarily 32-bit in such a case.
So it could be something like:

struct sched_param {
	int sched_priority;
	int __reserved1;
#if _REDIR_TIME64
	long __reserved2[4];
#else
	long long __reserved2[4];
#endif
	int __reserved3;
};

Note that the only reason this is needed is x32; otherwise, long would
always be the right size to match the old time_t. But in the other
places, it's more useful:

struct rusage {
#if _REDIR_TIME64
	struct {
		long tv_sec, tv_usec;
	} __ru_utime32, __ru_stime32;
#else
	struct timeval ru_utime;
	struct timeval ru_stime;
#endif
	/* linux extentions, but useful */
	long	ru_maxrss;
	long	ru_ixrss;
	long	ru_idrss;
	long	ru_isrss;
	long	ru_minflt;
	long	ru_majflt;
	long	ru_nswap;
	long	ru_inblock;
	long	ru_oublock;
	long	ru_msgsnd;
	long	ru_msgrcv;
	long	ru_nsignals;
	long	ru_nvcsw;
	long	ru_nivcsw;
#if _REDIR_TIME64
	long    __reserved[8];
	struct timeval ru_utime;
	struct timeval ru_stime;
#else
	long    __reserved[16];
#endif
};

Note that using the reserved space to avoid increasing the size here
isn't really useful, since the alignment requirement may change too
due to introduction of 64-bit members, but it might make things more
robust against ABI mismatches (likely SIGBUS instead of OOB
load/store).

Rich


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC] final time64 switch-over patch series
  2019-08-04  4:31 ` Rich Felker
@ 2019-08-09 16:30   ` Rich Felker
  2019-08-09 17:00     ` Rich Felker
  0 siblings, 1 reply; 10+ messages in thread
From: Rich Felker @ 2019-08-09 16:30 UTC (permalink / raw)
  To: musl

[-- Attachment #1: Type: text/plain, Size: 1432 bytes --]

On Sun, Aug 04, 2019 at 12:31:09AM -0400, Rich Felker wrote:
> On Fri, Aug 02, 2019 at 05:44:33PM -0400, Rich Felker wrote:
> > >From 3c6bde03ecf2aa7dac605f0a55a1be201f3d4c5f Mon Sep 17 00:00:00 2001
> > From: Rich Felker <dalias@aerifal.cx>
> > Date: Fri, 2 Aug 2019 15:41:27 -0400
> > Subject: [PATCH 5/5] [RFC] [POC] switch i386 to 64-bit time_t
> > 
> > this is a proof of concept for converting one 32-bit arch, i386, to
> > 64-bit time_t. known issues:
> > 
> > 1. the switchover of timespec padding is a hack, and needs to be done
> > right, but that involves making alltypes.h aware of endianness, which
> > probably should have been done a long time ago anyway and would get
> > rid of inappropriate inclusion of <endian.h> in some places.
> > 
> > 2. the rusage, utmpx, and timex structs are not correct with regard to
> > ABI or functionality. they need to be fixed before this is safe to
> > use.
> > 
> > 3. Makefile change should be its own thing.
> > 
> > there are likely a lot more problems.
> 
> Add a significant incomplete prerequisite I forgot about: dlsym. There
> needs to be a redirection for dlsym, and 32-bit archs need a second
> asm entry point for __dlsym_time64 which first checks the symbol name
> against the list of time64 redirections and rewrites the request if
> it's a match.

For reference, here's the first draft of the redirection. The worst
part of it is the large relro string table.

Rich

[-- Attachment #2: dlsym_redir_time64.c --]
[-- Type: text/plain, Size: 3034 bytes --]

#include <dlfcn.h>
#include <string.h>
#include <stdlib.h>
#include "dynlink.h"

const char *const mapping[][2] = {
{ "adjtime", "__adjtime64" },
{ "adjtimex", "__adjtimex_time64" },
{ "aio_suspend", "__aio_suspend_time64" },
{ "clock_adjtime", "__clock_adjtime64" },
{ "clock_getres", "__clock_getres_time64" },
{ "clock_gettime", "__clock_gettime64" },
{ "clock_nanosleep", "__clock_nanosleep_time64" },
{ "clock_settime", "__clock_settime64" },
{ "cnd_timedwait", "__cnd_timedwait_time64" },
{ "ctime", "__ctime64" },
{ "ctime_r", "__ctime64_r" },
{ "difftime", "__difftime64" },
{ "dlsym", "__dlsym_time64" },
{ "fstat", "__fstat_time64" },
{ "fstatat", "__fstatat_time64" },
{ "ftime", "__ftime64" },
{ "futimens", "__futimens_time64" },
{ "futimes", "__futimes_time64" },
{ "futimesat", "__futimesat_time64" },
{ "getitimer", "__getitimer_time64" },
{ "getrusage", "__getrusage_time64" },
{ "gettimeofday", "__gettimeofday_time64" },
{ "gmtime", "__gmtime64" },
{ "gmtime_r", "__gmtime64_r" },
{ "localtime", "__localtime64" },
{ "localtime_r", "__localtime64_r" },
{ "lstat", "__lstat_time64" },
{ "lutimes", "__lutimes_time64" },
{ "mktime", "__mktime64" },
{ "mq_timedreceive", "__mq_timedreceive_time64" },
{ "mq_timedsend", "__mq_timedsend_time64" },
{ "mtx_timedlock", "__mtx_timedlock_time64" },
{ "nanosleep", "__nanosleep_time64" },
{ "ppoll", "__ppoll_time64" },
{ "pselect", "__pselect_time64" },
{ "pthread_cond_timedwait", "__pthread_cond_timedwait_time64" },
{ "pthread_mutex_timedlock", "__pthread_mutex_timedlock_time64" },
{ "pthread_rwlock_timedrdlock", "__pthread_rwlock_timedrdlock_time64" },
{ "pthread_rwlock_timedwrlock", "__pthread_rwlock_timedwrlock_time64" },
{ "pthread_timedjoin_np", "__pthread_timedjoin_np_time64" },
{ "recvmmsg", "__recvmmsg_time64" },
{ "sched_rr_get_interval", "__sched_rr_get_interval_time64" },
{ "select", "__select_time64" },
{ "sem_timedwait", "__sem_timedwait_time64" },
{ "semtimedop", "__semtimedop_time64" },
{ "setitimer", "__setitimer_time64" },
{ "settimeofday", "__settimeofday_time64" },
{ "sigtimedwait", "__sigtimedwait_time64" },
{ "stat", "__stat_time64" },
{ "stime", "__stime64" },
{ "thrd_sleep", "__thrd_sleep_time64" },
{ "time", "__time64" },
{ "timegm", "__timegm_time64" },
{ "timer_gettime", "__timer_gettime64" },
{ "timer_settime", "__timer_settime64" },
{ "timerfd_gettime", "__timerfd_gettime64" },
{ "timerfd_settime", "__timerfd_settime64" },
{ "timespec_get", "__timespec_get_time64" },
{ "utime", "__utime64" },
{ "utimensat", "__utimensat_time64" },
{ "utimes", "__utimes_time64" },
{ "wait3", "__wait3_time64" },
{ "wait4", "__wait4_time64" },
};

static int cmp(const void *a, const void *b)
{
	return strcmp(*(const char *const *)a, *(const char *const *)b);
}

hidden void *__dlsym_redir_time64(void *restrict p, const char *restrict s, void *restrict ra)
{
	const char *const *map = bsearch(&(const char *const[]){s, 0}, mapping,
		sizeof mapping/sizeof mapping[0],
		sizeof mapping[0], cmp);
	return __dlsym(p, map ? map[1] : s, ra);
}

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC] final time64 switch-over patch series
  2019-08-09 16:30   ` Rich Felker
@ 2019-08-09 17:00     ` Rich Felker
  0 siblings, 0 replies; 10+ messages in thread
From: Rich Felker @ 2019-08-09 17:00 UTC (permalink / raw)
  To: musl

[-- Attachment #1: Type: text/plain, Size: 1793 bytes --]

On Fri, Aug 09, 2019 at 12:30:21PM -0400, Rich Felker wrote:
> On Sun, Aug 04, 2019 at 12:31:09AM -0400, Rich Felker wrote:
> > On Fri, Aug 02, 2019 at 05:44:33PM -0400, Rich Felker wrote:
> > > >From 3c6bde03ecf2aa7dac605f0a55a1be201f3d4c5f Mon Sep 17 00:00:00 2001
> > > From: Rich Felker <dalias@aerifal.cx>
> > > Date: Fri, 2 Aug 2019 15:41:27 -0400
> > > Subject: [PATCH 5/5] [RFC] [POC] switch i386 to 64-bit time_t
> > > 
> > > this is a proof of concept for converting one 32-bit arch, i386, to
> > > 64-bit time_t. known issues:
> > > 
> > > 1. the switchover of timespec padding is a hack, and needs to be done
> > > right, but that involves making alltypes.h aware of endianness, which
> > > probably should have been done a long time ago anyway and would get
> > > rid of inappropriate inclusion of <endian.h> in some places.
> > > 
> > > 2. the rusage, utmpx, and timex structs are not correct with regard to
> > > ABI or functionality. they need to be fixed before this is safe to
> > > use.
> > > 
> > > 3. Makefile change should be its own thing.
> > > 
> > > there are likely a lot more problems.
> > 
> > Add a significant incomplete prerequisite I forgot about: dlsym. There
> > needs to be a redirection for dlsym, and 32-bit archs need a second
> > asm entry point for __dlsym_time64 which first checks the symbol name
> > against the list of time64 redirections and rewrites the request if
> > it's a match.
> 
> For reference, here's the first draft of the redirection. The worst
> part of it is the large relro string table.

Here's a v2, also for historical reference, using arrays without
pointers to trade ~2k of additional pure-rodata space for ~500 bytes
of per-task dirty relro space.

I have a better design in mind already so this probably won't be used.

Rich

[-- Attachment #2: dlsym_redir_time64.c --]
[-- Type: text/plain, Size: 3008 bytes --]

#include <dlfcn.h>
#include <string.h>
#include <stdlib.h>
#include "dynlink.h"

static const struct mapping {
	char from[28];
	char to[36];
} mapping[] = {
{ "adjtime", "__adjtime64" },
{ "adjtimex", "__adjtimex_time64" },
{ "aio_suspend", "__aio_suspend_time64" },
{ "clock_adjtime", "__clock_adjtime64" },
{ "clock_getres", "__clock_getres_time64" },
{ "clock_gettime", "__clock_gettime64" },
{ "clock_nanosleep", "__clock_nanosleep_time64" },
{ "clock_settime", "__clock_settime64" },
{ "cnd_timedwait", "__cnd_timedwait_time64" },
{ "ctime", "__ctime64" },
{ "ctime_r", "__ctime64_r" },
{ "difftime", "__difftime64" },
{ "dlsym", "__dlsym_time64" },
{ "fstat", "__fstat_time64" },
{ "fstatat", "__fstatat_time64" },
{ "ftime", "__ftime64" },
{ "futimens", "__futimens_time64" },
{ "futimes", "__futimes_time64" },
{ "futimesat", "__futimesat_time64" },
{ "getitimer", "__getitimer_time64" },
{ "getrusage", "__getrusage_time64" },
{ "gettimeofday", "__gettimeofday_time64" },
{ "gmtime", "__gmtime64" },
{ "gmtime_r", "__gmtime64_r" },
{ "localtime", "__localtime64" },
{ "localtime_r", "__localtime64_r" },
{ "lstat", "__lstat_time64" },
{ "lutimes", "__lutimes_time64" },
{ "mktime", "__mktime64" },
{ "mq_timedreceive", "__mq_timedreceive_time64" },
{ "mq_timedsend", "__mq_timedsend_time64" },
{ "mtx_timedlock", "__mtx_timedlock_time64" },
{ "nanosleep", "__nanosleep_time64" },
{ "ppoll", "__ppoll_time64" },
{ "pselect", "__pselect_time64" },
{ "pthread_cond_timedwait", "__pthread_cond_timedwait_time64" },
{ "pthread_mutex_timedlock", "__pthread_mutex_timedlock_time64" },
{ "pthread_rwlock_timedrdlock", "__pthread_rwlock_timedrdlock_time64" },
{ "pthread_rwlock_timedwrlock", "__pthread_rwlock_timedwrlock_time64" },
{ "pthread_timedjoin_np", "__pthread_timedjoin_np_time64" },
{ "recvmmsg", "__recvmmsg_time64" },
{ "sched_rr_get_interval", "__sched_rr_get_interval_time64" },
{ "select", "__select_time64" },
{ "sem_timedwait", "__sem_timedwait_time64" },
{ "semtimedop", "__semtimedop_time64" },
{ "setitimer", "__setitimer_time64" },
{ "settimeofday", "__settimeofday_time64" },
{ "sigtimedwait", "__sigtimedwait_time64" },
{ "stat", "__stat_time64" },
{ "stime", "__stime64" },
{ "thrd_sleep", "__thrd_sleep_time64" },
{ "time", "__time64" },
{ "timegm", "__timegm_time64" },
{ "timer_gettime", "__timer_gettime64" },
{ "timer_settime", "__timer_settime64" },
{ "timerfd_gettime", "__timerfd_gettime64" },
{ "timerfd_settime", "__timerfd_settime64" },
{ "timespec_get", "__timespec_get_time64" },
{ "utime", "__utime64" },
{ "utimensat", "__utimensat_time64" },
{ "utimes", "__utimes_time64" },
{ "wait3", "__wait3_time64" },
{ "wait4", "__wait4_time64" },
};

static int cmp(const void *a, const void *b)
{
	return strcmp(a, b);
}

hidden void *__dlsym_redir_time64(void *restrict p, const char *restrict s, void *restrict ra)
{
	const struct mapping *map = bsearch(s, mapping,
		sizeof mapping/sizeof mapping[0],
		sizeof mapping[0], cmp);
	return __dlsym(p, map ? map->to : s, ra);
}

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC] final time64 switch-over patch series
  2019-08-02 21:44 [RFC] final time64 switch-over patch series Rich Felker
                   ` (2 preceding siblings ...)
  2019-08-09 14:48 ` Rich Felker
@ 2019-08-14 23:55 ` Rich Felker
  2019-08-15  0:13   ` Rich Felker
  3 siblings, 1 reply; 10+ messages in thread
From: Rich Felker @ 2019-08-14 23:55 UTC (permalink / raw)
  To: musl

On Fri, Aug 02, 2019 at 05:44:33PM -0400, Rich Felker wrote:
> From 84a4c907b8ea52e11f8edb9ccc1050e31753e5ca Mon Sep 17 00:00:00 2001
> From: Rich Felker <dalias@aerifal.cx>
> Date: Wed, 31 Jul 2019 15:24:58 -0400
> Subject: [PATCH 1/5] add time64 symbol name redirects to public headers, under
>  arch control
> 
> a _REDIR_TIME64 macro is introduced, which the arch's alltypes.h is
> expected to define, to control redirection of symbol names for
> interfaces that involve time_t and derived types. this ensures that
> object files will only be linked to libc interfaces matching the ABI
> whose headers they were compiled against.
> 
> along with time32 compat shims, which will be introduced separately,
> the redirection also makes it possible for a single libc (static or
> shared) to be used with object files produced with either the old
> (32-bit time_t) headers or the new ones after 64-bit time_t switchover
> takes place. mixing of such object files (or shared libraries) in the
> same program will also be possible, but must be done with care; ABI
> between libc and a consumer of the libc interfaces is guaranteed to
> match by the the symbol name redirection, but pairwise ABI between
> consumers of libc that define interfaces between each other in terms
> of time_t is not guaranteed to match.
> 
> this change adds a dependency on an additional "GNU C" feature to the
> public headers for existing 32-bit archs, which is generally
> undesirable; however, the feature is one which glibc has depended on
> for a long time, and thus which any viable alternative compiler is
> going to need to provide. 64-bit archs are not affected, nor will
> future 32-bit archs be, regardless of whether they are "new" on the
> kernel side (e.g. riscv32) or just newly-added (e.g. a new sparc or
> xtensa port). the same applies to newly-added ABIs for existing
> machine-level archs.
> ---
>  include/aio.h          |  4 ++++
>  include/mqueue.h       |  5 +++++
>  include/poll.h         |  6 ++++++
>  include/pthread.h      | 10 ++++++++++
>  include/sched.h        |  4 ++++
>  include/semaphore.h    |  4 ++++
>  include/signal.h       |  8 ++++++++
>  include/sys/resource.h |  4 ++++
>  include/sys/select.h   |  5 +++++
>  include/sys/sem.h      |  6 ++++++
>  include/sys/socket.h   |  6 ++++++
>  include/sys/stat.h     |  9 +++++++++
>  include/sys/time.h     | 14 ++++++++++++++
>  include/sys/timeb.h    |  4 ++++
>  include/sys/timerfd.h  |  5 +++++
>  include/sys/timex.h    |  5 +++++
>  include/sys/wait.h     |  7 +++++++
>  include/threads.h      |  6 ++++++
>  include/time.h         | 28 ++++++++++++++++++++++++++++
>  include/utime.h        |  4 ++++
>  20 files changed, 144 insertions(+)
> 
> diff --git a/include/aio.h b/include/aio.h
> index 19bc28a9..482b2a70 100644
> --- a/include/aio.h
> +++ b/include/aio.h
> @@ -62,6 +62,10 @@ int lio_listio(int, struct aiocb *__restrict const *__restrict, int, struct sige
>  #define off64_t off_t
>  #endif
>  
> +#if _REDIR_TIME64
> +int aio_suspend() __asm__("__aio_suspend_time64");
> +#endif

These non-prototype declarations for the redirections are not going to
work, since they're not compatible with C++. So either:

1. We repeat the full declarations with prototype, or
2. We use the GNU C __typeof__ for the redirections, or
3. We eliminate the separate #if _REDIR_TIME64 blocks and instead put
   conditionally-defined redirections on the end of the main
   declarations.

I kind of lean towards 3, in that it avoids the possibility of
introducing ABI-breaking bugs via inconsistency between the feature
test macro checks at the point of original declaration and the point
of redirection.

I don't like the verbosity and duplication of option 1. I don't like
the GNU C of option 2, but it's probably no worse than the __asm__ we
can't avoid anyway.

In order to do option 3 though we need a place to conditionally define
the macro appropriately. features.h seems natural but it doesn't
necessarily have access to alltypes.h without adding more inclusions
(which impacts compile times on all targets).

It should be possible to do some macro magic to make features.h do a
_T64() function-like macro that expands differently depending on the
definition of _REDIR_TIME64 at the time it's expanded, but this will
require that all archs define it to 0 or 1 rather than leaving it
undefined when not used. Then we can just unconditionally do:

int aio_suspend(const struct aiocb *const [], int, const struct timespec *) _T64(__aio_suspend_time64);

etc.

Does this seem reasonable?

Rich


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC] final time64 switch-over patch series
  2019-08-14 23:55 ` Rich Felker
@ 2019-08-15  0:13   ` Rich Felker
  2019-08-15  0:30     ` Rich Felker
  0 siblings, 1 reply; 10+ messages in thread
From: Rich Felker @ 2019-08-15  0:13 UTC (permalink / raw)
  To: musl

On Wed, Aug 14, 2019 at 07:55:21PM -0400, Rich Felker wrote:
> It should be possible to do some macro magic to make features.h do a
> _T64() function-like macro that expands differently depending on the
> definition of _REDIR_TIME64 at the time it's expanded, but this will
> require that all archs define it to 0 or 1 rather than leaving it
> undefined when not used. Then we can just unconditionally do:
> 
> int aio_suspend(const struct aiocb *const [], int, const struct timespec *) _T64(__aio_suspend_time64);
> 
> etc.
> 
> Does this seem reasonable?

Hm, I think it's probably simpler/more readable just to have
alltypes.h define _T64(x) appropriately. I hate header mechanisms that
require you to trace back across arcane stuff in multiple places to
find how/where something is actually defined.

Rich


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC] final time64 switch-over patch series
  2019-08-15  0:13   ` Rich Felker
@ 2019-08-15  0:30     ` Rich Felker
  0 siblings, 0 replies; 10+ messages in thread
From: Rich Felker @ 2019-08-15  0:30 UTC (permalink / raw)
  To: musl

On Wed, Aug 14, 2019 at 08:13:31PM -0400, Rich Felker wrote:
> On Wed, Aug 14, 2019 at 07:55:21PM -0400, Rich Felker wrote:
> > It should be possible to do some macro magic to make features.h do a
> > _T64() function-like macro that expands differently depending on the
> > definition of _REDIR_TIME64 at the time it's expanded, but this will
> > require that all archs define it to 0 or 1 rather than leaving it
> > undefined when not used. Then we can just unconditionally do:
> > 
> > int aio_suspend(const struct aiocb *const [], int, const struct timespec *) _T64(__aio_suspend_time64);
> > 
> > etc.
> > 
> > Does this seem reasonable?
> 
> Hm, I think it's probably simpler/more readable just to have
> alltypes.h define _T64(x) appropriately. I hate header mechanisms that
> require you to trace back across arcane stuff in multiple places to
> find how/where something is actually defined.

OK, I started a draft for this and I hate it. It spreads the change
all out interspersed with content that's generic and has nothing to do
with time64-specific archs or even with musl, and makes the headers
gratuitously dependent on a musl-specific _T64 macro being defined
(even if defined away as nothing).

I should probably go the __typeof__ route...

Rich


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2019-08-15  0:30 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-08-02 21:44 [RFC] final time64 switch-over patch series Rich Felker
2019-08-04  4:31 ` Rich Felker
2019-08-09 16:30   ` Rich Felker
2019-08-09 17:00     ` Rich Felker
2019-08-04  4:33 ` Rich Felker
2019-08-04 18:11   ` Rich Felker
2019-08-09 14:48 ` Rich Felker
2019-08-14 23:55 ` Rich Felker
2019-08-15  0:13   ` Rich Felker
2019-08-15  0:30     ` Rich Felker

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/musl/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).