# musl time64 Release Notes musl 1.2.0 changes the definition of `time_t`, and thereby the definitions of all derived types, to be 64-bit across all archs. This and related changes are collectively referred to as "time64", and are necessary so that data types and functions dealing with time can represent time past early 2038, where the existing 32-bit type on 32-bit archs would overflow. ## Caveats Individual users and distributions upgrading 32-bit systems to musl 1.2.x need to be aware of a number of ways things can break with the time64 transition, most of them outside the scope and control of musl itself. These are discussed in detail below. 64-bit systems are unchanged and are not affected by any of the following. ### Library ABIs musl 1.2.0 does not change or remove any part of the existing ABI between libc and libc consumers (that is, applications or libraries using libc-defined types/interfaces). In this sense, it is non-ABI-breaking. Existing binaries built against musl prior to the time64 change will run against new musl `libc.so`, and existing object files can even be static-linked against the new `libc.a`. However, the types defined by libc can also participate in the interface boundaries between pairs of libc consumers (application-library or library-library), and when this happens, an ABI mismatch will arise if they were built with mismatching definitions of `time_t`. Prior to the start of the time64 conversion of musl, [a list of potentially affected libraries][1] was generated programmatically from Debian package repository header files and metadata. Applications and libraries that do not use any of these libraries should be safe to rebuild for time64 or hold back independently. Applications and libraries which do use one of the affected libraries may need to be rebuilt in sync with that library, to avoid ABI mismatch. System integrators and distributions need to make their own determination as to whether it makes sense to use package dependency/conflict tracking to ensure that such upgrades are made in sync where needed, or to impose global updates to time64. ### Kernel Headers musl itself does not use kernel headers whatsoever. However, if building applications or libraries which do use them, particularly anything making use of ALSA, v4l, or evdev/input, you must build against sufficiently new kernel headers. As of Linux 4.19, all important kernel header fixes except those needed by asound/ALSA are upstream. The latter were not ready for 5.4, and are expected to land in 5.6. [An aggregate patch][2] to make the necessary header changes is shipped with musl-cross-make, but it's incompatible with actually building the kernel, so headers need to be built/installed separately if using it. ### Application Compatibility Some applications are not ready upstream for running in a time64 environment on 32-bit. Possible issues include: - Use of kernel APIs that require changes for time64 compatibility - `struct input_event` from `linux/input.h` (libinput, qemu-system, Xorg input device modules, ...) - Bluetooth `HCI_TIME_STAMP` socket option (BlueZ) - Filtering/tracing/interception of system calls - Interpretation of syscall argument structures needs to use kernel UAPI types, not libc types (strace). - Seccomp filters need to allow new time64 versions of syscalls (OpenSSH sshd, Firefox, Chromium, ...). - Intercepting/wrapping of libc functions via `dlsym`/`RTLD_NEXT` (fakeroot, ...) - As long as interceptor uses headers correctly, it should just work, but will only work with new time64 binaries not legacy ones. - [A compat stub library][3] can be linked into such interceptors to make them simultaneously work with legacy binaries. - Outdated, time64-incompatible kernel headers shipped with the application (alsa-lib) - Direct use of syscalls with `time_t`-derived arguments (libstdc++, Busybox, non-C language runtimes, ...) - Undefined behavior and unwarranted assumptions - Manual declaration of time functions or types, bypassing or suppressing definitions in libc headers (Berkeley DB, doxygen). - Use of `%ld` format to print `time_t` or `suseconds_t`. - Access to time structures in objects not suitably aligned. [Adélie Linux][4] and [Yoe/Yocto/OpenEmbedded][5] did the early groundwork building large package corpuses against time64 musl during the 1.2.0 release cycle and found and patched all build-time breakage found, as well as obvious run-time problems. Some of these patches are now upstream in the corresponding projects. The [Adélie time64 wiki page][6] is a good starting point for information about packages that need patching. ## Implementation of the transition ### New time64 symbols To change the definition of `time_t` and all derived types without breaking the ABI boundary between libc-consumers and libc, musl 1.2.0 redirects all functions using these types as part of their interface to alternate symbol names via the `__asm__("name")` construct in their declarations in the public headers. To be namespace-clean, the redirected names all begin with double-underscore. Otherwise, the pattern for naming follows the Linux kernel's pattern for syscall names: if the name ends in "time", "64" is appended; otherwise, "_time64" is appended. A final "_r", if present, is removed and re-added before and after the renaming, so that, for example, `gmtime_r` becomes `__gmtime64_r`, not `__gmtime_r_time64`. This symbol redirection introduces a depedency (for existing 32-bit archs) on an additional "GNU C" feature, but it is one which glibc has depended on for handling its `_FILE_OFFSET_BITS=64` feature for decades, and one which any viable alternative-compiler already needs to implement. Since these functions depend on `time_t` or derived types defined by the headers, conforming applications cannot bypass the headers and use their own declarations; they're required by the standards (C and POSIX) to include the headers. The `dlsym` function is also redirected, to a version that redirects names for affected functions, so that programs which lookup one of them by its symbol name get the correct version using matching types. ### Legacy compatibility musl does not retain duplicate implementations for legacy ("time32") versions of the functions. Instead, they are all thin wrappers defined in the new `compat/time32` source tree. These wrappers generally just convert the affected input structures from time32 to time64 form, convert the affected output structures from time64 to time32 form, and if possible, translate values that overflow into errors. (Such translation is not possible, however, if the function already performed an operation with side effects.) ### Syscall usage Internally, functions which use time only as an input perform the old time32 syscall as long as the value is representable in 32 bits. This avoids having to fail and fallback on older kernels. Functions that produce time as an output have to start with the time64 syscall, in case the value does not fit in 32 bits, and fallback if the new syscall is not available. `clock_gettime` would be the most-impacted by this in terms of performance, but as long as vdso version is available, it's used to avoid the need for making a syscall at all. Both the time64 and legacy time32 versions of the vdso function are supported. ### Socket option, ancillary data, and `ioctl` translation A number of socket options and `ioctl` commands involve `time_t`-derived types. These all have new values defined by Linux, which will necessarily be missing from older kernels. musl contains code to handle the case where they are missing and translate to/from the appropriate argument forms for the old 32-bit versions. A few socket options, particularly the `SO_TIMESTAMP` family, cause ancillary data to be delivered to the application along with socket reads via `recvmsg` and `recvmmsg`. These functions now translate 32-bit versions of the ancillary data if found, and append a 64-bit translation of it, so that both legacy time32 binaries and time64 binaries running on old kernels work correctly. On new kernels with the native time64 socket options, no translation is necessary. [1]: https://www.openwall.com/lists/musl/2019/07/02/2 [2]: https://raw.githubusercontent.com/richfelker/musl-cross-make/3cfbdabfd63d2c8ca1024a87a44dae434b3291e1/patches/linux-4.19.90/0001-asound-time64.diff [3]: https://github.com/richfelker/libcompat_time32 [4]: https://www.adelielinux.org/ [5]: https://www.yoctoproject.org/ [6]: https://wiki.adelielinux.org/wiki/Project:Time64