-
Notifications
You must be signed in to change notification settings - Fork 13.2k
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
Using std::io::{Read, Write, Cursor} in a nostd environment #48331
Comments
The problem with this, which has been covered in previous issues, is that |
Do you have a link to previous issues ? I tried looking for it, but nothing came up :(. |
I... can't find the previous issues. Maybe it was just scattered comments over the place and IRC discussions... |
These traits being absent is the reason rust-core_io exists. Relibc would thank you if |
Anything here requires the We should explore replacing In essence, it should act like We could maybe preserve Also, I'm unsure if
We must then use wrapper types that handle drop correctly.
We then need some outer type that calls
|
Backtrace cannot really exist outside std. It is highly dependent on OS features. For instance, to get function names (symbolication step of printing a backtrace), it requires opening the executable as a file and parsing it to access the debug information table, e.g. it requires doing open(argv[0]). Or it might require dlresolve or other kind of libc stuff. In an ideal world, binaries compiled in no_std could just have an "empty" implementation of Backtraces. I don't think that's possible however, since libstd simply reexports everything in libcore verbatim. It's not possible for libstd to use a different implementation of things than libcore AFAICT. Unfortunately, moving backtraces to be an exposed interface of std::error::Error seems to permanently kill any possibility of std::error and std::io being available in libcore. |
Could we replace |
Std cannot (currently) add inherent impls for structs it does not itself define. It plays by the same rule as the rest of the ecosystem when it comes to coherence, there's no magic going on here (modulo some escape hatches for fundamental types that don't apply here). Libstd can implement libstd traits on libcore structs, or implement libcore traits for libstd structs. But it can't add its own inherent impls for (libcore) structs, only the crate defining a type can do that. The best I can figure out is changing the backtrace function to return a Except that's also undesirable because now all the errors living in libcore won't get to use backtraces - only errors in libstd would use the "right" backtrace implementation. Maybe that'd be fixable using the same mechanism global allocators use? Have some kind of backtrace factory, have libstd give out a default implementation, and ask libcore users to provide their own (probably stubbed) implementation. |
I suppose std cannot use features for dependencies like many crates do if we want std to ever actually be the standard library on some future operating system. In other words, if features are additive then std should always have all its features enabled. I think
I still think As for implementation, there are several options here:
|
I think We'd need to remove the It appears We should reimplement the I think We should also remove the backtrace that After all this we could then reimplement all traits from |
This allows most implementers of `BinRead` to use std features on the reader instead of restricting them to the subset of features exposed by the no_std reimplementation. This also appears to have been the original intent of the `binread::io` module, per the module-level comment. This is a breaking change because `iter_bytes` is called `bytes` in std and consumes the reader, so this has been changed in the binread implementation to conform to that API. This commit also fixes the earlier binread implementations not handling errors as std does; this is now fixed (by copying from std). (Hopefully rust-lang/rust#48331 will be addressed someday and then this code can disappear entirely.)
This allows most implementers of `BinRead` to use std features on the reader instead of restricting them to the subset of features exposed by the no_std reimplementation. This also appears to have been the original intent of the `binread::io` module, per the module-level comment. This is a breaking change because `iter_bytes` is called `bytes` in std and consumes the reader, so this has been changed in the binread implementation to conform to that API. This commit also fixes the earlier binread implementations not handling errors as std does; this is now fixed (by copying from std). (Hopefully rust-lang/rust#48331 will be addressed someday and then this code can disappear entirely.)
This allows most implementers of `BinRead` to use std features on the reader instead of restricting them to the subset of features exposed by the no_std reimplementation. This also appears to have been the original intent of the `binread::io` module, per the module-level comment. This is a breaking change because `iter_bytes` is called `bytes` in std and consumes the reader, so this has been changed in the binread implementation to conform to that API. This commit also fixes the earlier binread implementations not handling errors as std does; this is now fixed (by copying from std). (Hopefully rust-lang/rust#48331 will be addressed someday and then this code can disappear entirely.)
This allows most implementers of `BinRead` to use std features on the reader instead of restricting them to the subset of features exposed by the no_std reimplementation. This also appears to have been the original intent of the `binread::io` module, per the module-level comment. This is a breaking change because `iter_bytes` is called `bytes` in std and consumes the reader, so this has been changed in the binread implementation to conform to that API. This commit also fixes the earlier binread implementations not handling errors as std does; this is now fixed (by copying from std). (Hopefully rust-lang/rust#48331 will be addressed someday and then this code can disappear entirely.)
#99917 has been merged so is anyone going to create a PR? |
I think it needs a lot more discussion. It returns See rust-lang/project-error-handling#11 on some of the challenges there, and discussion if doing so is even desirable. My personal stance is that it should be closer to something like |
Thank you for the explanation @thomcc. Here goes a copy-and-paste of As seen above, the only thing preventing the inclusion of Not sure if the the new provider API can help here but if not, then |
I feel like, there could be already an |
Hello 👋 [This advisory](GHSA-x4mq-m75f-mx8m) has been bothering me since a while. The origin of it is [`acid_io`](https://github.com/dataphract/acid_io/blob/v0.1.0/Cargo.toml#L28), where the [issue has been fixed](dataphract/acid_io#21), but no release has been publish 😞 (since 3 years!) So, after reading this [discussion/issue](rust-lang/rust#48331), I decided to replace `acid_io` for [`core2`](https://crates.io/crates/core2) (which seems quite used, even if the last release was 2 years ago). The changes was trivial as `acid_io` and `core2::io` have the same API as `std::io`. But, while trying to test those changes, the CI failed (which was also the case [`last week`](https://github.com/dequbed/rsasl/actions/runs/8870496836)). So I started to fix the CI, and made changes to make the CI pass. I also added a `dependabot.yaml`, PR will be created monthly to update the dependencies in the `Cargo.toml` and `ci.yml`. I formatted the `README.md` and `Cargo.toml`. I had to bump MSRV to 1.65. I bumped the dependencies to their latest versions, and pushed the `Cargo.lock`, see [`why`](https://doc.rust-lang.org/cargo/faq.html#why-have-cargolock-in-version-control). And I ran `cargo clippy --fix` and `cargo fmt`, with not much modification from myself. I just finished to write the description of this PR and realize that someone was working on #36, oops
Now that |
Changing the error type would be a break. Moving the existing error type likely still has problems, which are solvable but which aren't actually solved yet. |
Yeah, the issue is the io::Error type, not the error::Error trait. Currently, the former requires alloc/Box, making it difficult to move into core. |
Just out of curiosity, everything will work fine if they're moved into |
The fact that I'm surprised that there are not that many people complaining about it. In 2025, 7 years after this issue was opened, what do people to workaround it? What's the go to solution? Are there any sights on addressing this issue? Any conclusions on what approach would be ideal? Could we maybe get new |
I did create #116685 as a demo of how |
|
Another reason to just have separate io traits in What |
I haven't seen |
I might have missed this issue when I looked for it in the past, not sure. Part of the problem is that I needed a solution now (and about three years ago), but I would be very grateful to see some progress on
So I am actually dealing with interesting environments that either need a custom std or that need to use One such environment is Intel SGX, where you don't have actual I/O inside enclaves, but can implement OCALLs to interface the operating system indirectly through the untrusted userspace application loading your enclave. Thus, you can expose enough of the libc API to the enclave to implement most of the Rust standard library. From what I know Fortanix went the route of having a custom target with its own implementation of the Rust standard library (thus avoiding the need for Another such environment is DynamoRIO (and Intel Pin), which is an instrumentation framework. This means that you can write DynamoRIO clients which can trace programs as they execute and even manipulate the code. However, as the program should not be aware of the existence of such DynamoRIO clients, the clients have to adhere to certain restrictions, including that they cannot use libc directly (thus, by extension the Rust standard library). Also, because using libc directly can alter the program's behavior and memory layout. However, as you often need libc in DynamoRIO clients, DynamoRIO provides its own API that allows you to access the file system, create threads, etc. without possibly altering the program's behavior. I have successfully implemented DynamoRIO bindings for Rust using I have also looked at embedded-io and ciborium-io, but they are just less complete compared to the no_std_io crate. This might be fine for embedded I/O, but it doesn't make as much sense if you can actually implement most of Rust's standard library and just want to offer a batteries-included experience. This is also why I like to create awareness of such environments where you can actually implement a standard library (albeit with some caveats), but might need |
Relevant xkcd We do not want to use an alternative. We want the standard implementation to be actually standard. |
I'm surprised there's no ticket for this, so here we go.
It isn't possible in nostd to use std::io::Cursor. That seems to be mostly because it requires std::io::Read, Write, and Seek. However, I'd argue that those traits should also be part of libcore, and only the specific implementations be in libstd. After all, the Read/Write/Seek traits and the Cursor struct don't seem to rely on anything that's part of the stdlib: they don't need allocation, etc...
My use-case is, I have to write data into an array, and treating that array in a file would lead to much more idiomatic code. Furthermore it'd allow using crates like byteorder in nostd environment.
The text was updated successfully, but these errors were encountered: