-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use the glibc 64bit time APIs to mitigate the Y2038 problem on 32bit platforms #3223
Comments
I've submitted #3175 as a possible solution. |
If somebody needs something like crate libc, but without time32 and lfs problems, I suggest using crate rustix. You can read its code and see that rustix put a lot of effort to deal with time32 and lfs problems |
I can see how that would work if I control which crates I want to use. But I'm not designing these projects from scratch, I'm trying to build existing projects with plenty of dependencies that use the libc crate. If it is not obvious: I don't know much about rust, I'm approaching this from a distro building perspective using the Yocto project. |
regardless of whether rustix works or not, libc has to be fixed anyway (i.e. this is lacking platform support and a goal of |
I think the sensible solution here is to simply use 64 bits version of these types in every platform that supports them. In this time and age, I think it makes no sense for Rust's It is not like we have to worry about not breaking a huge ecosystem of 30 years old code that assumes these types to be 32 bits, like they have to in C. |
Will this be part of the 0.3 release? I see a lot of talk about the same problem on musl. |
cc @joshtriplett as you facilitate the libc 0.3 here: #3248 |
The main concern here is compatibility with C code that we link to using FFI. If some C code uses This is similar to the situation with 64-bit |
I understand your concern. But won't that be just as big a problem if the library has been built with the 64-bit flags set even if that is not the default for that library? Note that as long as the C library does not use any of the affected types such as My usecase is an embedded linux distribution created with Yocto. Everything is built from source and I control all the compiler settings. I need to make any Rust app build against 64-bit libs, and right now it seems my only option is to patch all uses of libc. For this, I would be happy with a switch I could set globally but I can see how that is not usable by everyone. |
Unfortunately there is just no way for Rust to know what flags any particular C code was compiled with. My recommendation would be to expose the time64 APIs in a Most Rust programs will not interact with the |
SystemTime and libc crate aren't using musl correctly either. I got the following on a 32 bit musl system after setting the system clock to 2040. I didn't yet look into details of what is happening, but please take this seriously: rust simply can't be used on 32 bit systems as of today, not if you want them to keep working after 2038:
|
Wouldn't using a |
Libc crate could check whether _TIME_BITS=64 is in CFLAGS (as prescribed by
glibc), and then build with 64 bit time. Same as what happens via glibc
header define magic in C components.
I’m not yet sure where things go wrong with musl (see above), need to look
into it.
|
After some poking at musl code, I think it has the same ABI as as glibc: clock_gettime() is the 32 bit version, and if you want 64 bits, you must call into __clock_gettime64(). C headers would take care of this automatically, but rust won't use them, so 🤷 musl's version of _TIME_BITS define is _REDIR_TIME64, and it's set to 1 by default in its headers (unlike glibc where you need to opt into 64 bit time via externally set -DTIME_BITS=64). |
@snogge you can change the title of this issue, I suppose. It's the same on glibc and musl. 32 bit api in use on both :( |
Thanks, I left a comment there. #3068 could serve as a template for adding glibc time64 support as well: enable cargo:rustc-cfg=glibc_time64_abi, if -D_TIME_BITS=64 is in CFLAGS. Then redirect everything to time64 symbols subject to that. Then rust-libc consumers need not know or care about which ABI to select (I strongly object to the above suggestion that they should - one will never be able to fix or validate correct usage in a complete system that way). |
I'll have a look at that later. I'm working on rebasing the PR right now. |
I do, and I'm working on rebasing and cleaning up my PR as we speak. |
@safinaskar the PR has been updated and is ready for review. |
There's also the problem here that Linux distributions are switching over to using This means that somehow the libc crate would have to be switched to the 64 bit definitions depending on not just on what a certain piece of C code usually uses, but also what the default of the whole system are. During the transition period, that effectively depends also on which build of a C library is currently in use. Quoting from the Debian wiki
that sounds like they actually missed this problem here. |
I'm not sure why this is a complication. This libc crate should check CFLAGS from the unix environment at build time, if -D_TIME_BITS=64 is there, enable that, otherwise don't. Then the OS build system would set CFLAGS depending on which libraries would be used (ideally it's just a system wide setting with no need to provide 32 bit time compatibility items). Is there some scenario where it wouldn't work? |
If we ignore the transitional aspect where some libraries are using 64 bit and others 32 bit * Not sure if it's safe to ignore the transitional aspect though. It doesn't seem like an impossible situation that users running a 64 bit Maybe I'm missing something here and this is all somehow taken care off. I didn't look too closely into this issue and only thought of the interactions with the |
The compiled GNU libc library always support both 32bit and 64bit time APIs and ABI. A C program that is built with the proper preprocessing options will use 64bit types and redirect to the 64bit APIs. |
For what it's worth, I'm coming from the Yocto project, which builds complete system images and associated package feeds completely from source. So we have the luxury of using global CFLAGS to enforce 64 bit time across the entire stack, with no exceptions and transitions and potential mixing of libraries. In this scenarion, we'd still want rust libc crate to honor that global setting, as otherwise it becomes impossible to tell if all components using that crate are doing the right thing. |
I don't see a good way to solve this. The fundamental issue is that we don't know what pre-processor definitions were used to build arbitrary C code we may want to link with. It could be system libraries built with We could do some probing in build.rs to check if the C compiler for the current target generates a 64-bit This unfortunately leaves us with very few options. I think the best way forward for libc is, for glibc targets, to:
It then becomes the user's responsibility to ensure that if they use the 64-bit symbols, they need to ensure that the C code they are using is built with the proper flags. The downside of this approach is that we are intentionally shipping deprecated functions, but I feel it is better this way because it gives users a chance to think twice in cases where there might be an incompatibility with C code that is being linked into the same binary. |
That was also my conclusion. It seems unsolveable in general, and even if you have a C compiler at hand you still don't know which of the two variants that C library in front of you was compiled with.
Unless I misunderstand you, I think the problem with this approach is that you actually make it the developer's responsibility (selecting which of the variants to use in their code) to solve a problem that depends on the user's choices (what the user's C libraries are compiled with). Let's say you're the maintainer of Apart from a build-time configuration and making this very clear in the documentation, (and having Debian/etc set this correctly for all their builds!), I don't see another way out of here. Of course a user building some random crate that somewhere deep in its dependency has Also as a side-note, this whole thing also affects |
Note that Debian plans to switch to time64 for many 32-bit archs, but not for i386, according to wiki: |
glibc is probably unique in supporting both variants. Eventually we will be in the situation that some versions of some distros on some archs use 64 bit time_t while the rest stick to 32 bit. And the libc crate will be incompatible with one of the sets. |
I'm not sure how this would be activated, but from Yocto perspective what is needed is that we can set a 'global setting' inside a complete system build that would be automatically picked up by all of the components that contain the libc crate. Right now that setting is having the -D_TIME_BITS=64 in CFLAGS environment variable, and if libc crate would pick up and respect that then that'd be perfect. |
Where, if a google search for Ubuntu noble release date is to be belived "Eventually" is in four days. Ubuntu noble (24.04) will be using time64 on armhf but not on i386. I would agree with Anvin that enabling this based on CFLAGS seems a reasonable first step, it's unlikely to break anything that isn't already broken and will fix things for some (but admittedly not all) usecases. Whether to add more elaborate detection is IMO a question that can be asked after the basic support is included. |
I could update the PR to check the |
This is correct, CFLAGS is not the canonical place to put these, and I was confused about where yocto puts them. There are various way to prescribe what ends up in C preprocessor, e.g. environment variables with command line flags, Makefiles, per-project config includes etc. That said, I would really appreciate at least having some environment variable that can be set by distro builders to force 64 bit time in rust libc in a complete system build. You can name it RUST_LIBC_USE_64BIT_TIME. We (the yocto project) willl take care of setting it as appropriate. |
AFAICS the most user-friendly way would be to check the target triplet, and Linux distro version from build.rs and based on that and a table auto-detect the variant of That probably won't work for Yocto though as there it's actually a configuration (can that be retrieved somehow easily?) and not a simple matter of checking a version. |
Isn't that what cargo is doing by passing the various CARGO_CFG variables? See the |
I'm also not keen on the hardcoded distro/version table idea. As far as I understand, the only remaining binary distro that has any interest at all in 32 bit computing (and fixing y2038 in it) is Debian. For yocto such auto-detection is not useful as it is a generator of custom distros, and especially if build.rs would try to read things in /etc to determine 'distro (and its version) it would make completely incorrect decisions. is_gnu_time64_abi() as it is has two problems:
I'd consider not trying to guess this at all, and just setting from environment variable only, as an opt-in. |
The riscv32 variant does not look at the gnu_time64 config option, or does so in a safe way, so is_gnu_time_64 does not have to handle it. |
I've updated #3175 to handle the cases listed above.
|
The GNU libc (glibc) provides alternative 64bit entry points for many of the file and time related functions on 32bit platforms. For C programs these are activated by setting the
-D_TIME_BITS=64
and-D_FILE_OFFSET_BITS=64
preprocessor flags. What happens is that all the relevant types (time_t
,blksize_t
, ...) are defined as 64bit integers and the called symbols are redirected from the standard 32-bit variant likegmtime
to a 64bit variant like__gmtime64
.In many ways this is the same as
-D_LARGEFILE_SOURCE
flag except that this will not add new types and symbols but replace the existing ones. Note that it is possible to use-D_LARGEFILE_SOURCE
and-D_FILE_OFFSET_BITS=64
at the same time.For full 64bit time support on llnux you also need a kernel newer than 5.6, but the 64bit glibc functions should be safe to use anyway and no worse than the 32bit versions.
The 64bit time support is needed when building embedded linux systems on 32bit platforms that are expected to live for 10 to 15 years.
The text was updated successfully, but these errors were encountered: