glibc is still not Y2038 compliant by default
Most of my readers are probably aware of the Y2038 issue by now. If not, it refers to 3:14:07 UTC on January 19, 2038, when 32-bit time_t
will overflow. The Linux kernel has internally switched to 64-bit timekeeping several years ago, and Alpine made the jump to 64-bit time_t
with the release of Alpine 3.13.
In the GNU/Linux world, the GNU libc started to support 64-bit time_t
in version 2.34. Unfortunately for the rest of us, the approach they have used to support 64-bit time_t
is technically deficient, following in the footsteps of other never-fully-completed transitions.
the right way to transition to new ABIs
In the musl C library, which Alpine uses, and in many other UNIX C library implementations, time_t
is always 64-bit in new code, and compatibility stubs are provided for code requiring the old 32-bit functions. As code is rebuilt over time, it automatically becomes Y2038-compliant without any effort.
Microsoft went another step further in msvcrt
: you get 64-bit time_t
by default, but if you compile with the _USE_32BIT_TIME_T
macro defined, you can still access the old 32-bit functions.
It should be noted that both approaches described above introduce zero friction to get the right thing.
how GNU handles transitions in GNU libc
The approach the GNU project have taken for transitioning to new ABIs is the exact opposite: you must explicitly ask for the new functionality, or you will never get it. This approach leaves open the possibility for changing the defaults in the future, but they have never ever done this so far.
This can be observed with the large file support extension, which is needed to handle files larger than 2GiB, you must always build your code with -D_FILE_OFFSET_BITS=64
. And, similarly, if you’re on a 32-bit system, and you do not build your app with -D_TIME_BITS=64
, it will not be built using an ABI that is Y2038-compliant.
This is the worst possible way to do this. Consider libraries: what if a dependency is built with -D_TIME_BITS=64
, and another dependency is built without, and they need to exchange struct timespec
or similar with each other? Well, in this case, your program will likely crash or have weird behavior, as you’re not consistently using the same struct timespec
in the program you’ve compiled.
Fortunately, if you are targeting 32-bit systems, and you would like to manipulate files larger than 2GiB or have confidence that your code will continue to work in the year 2038, there are Linux distributions that are built on musl, like Alpine, which will allow you to not have to deal with the idiosyncrasies of the GNU libc.