Skip to content
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

Allow CStr and CString types to be used with no_std #46736

Closed
clarfonthey opened this issue Dec 14, 2017 · 20 comments · Fixed by #94079
Closed

Allow CStr and CString types to be used with no_std #46736

clarfonthey opened this issue Dec 14, 2017 · 20 comments · Fixed by #94079
Labels
A-FFI Area: Foreign function interface (FFI) C-feature-request Category: A feature request, i.e: not implemented / a PR. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.

Comments

@clarfonthey
Copy link
Contributor

clarfonthey commented Dec 14, 2017

Embedded code may interact with C and thus may find these types useful. It'd make sense to allow usage of CStr in libcore and CString in liballoc.

Of course, right now due to the way implementations work in the standard library it may not be possible to include CStr in libcore. However, moving it to liballoc is still a step up.

@kennytm
Copy link
Member

kennytm commented Dec 15, 2017

Including CStr in libcore means the target-dependent type c_char will need to be in libcore as well.

@kennytm kennytm added C-feature-request Category: A feature request, i.e: not implemented / a PR. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. labels Dec 15, 2017
@clarfonthey
Copy link
Contributor Author

clarfonthey commented Dec 23, 2017

@kennytm in that case, it would make sense to just move the entire os::raw module over to libcore. I'd probably rename it, though, and put it as a submodule of ffi.

@kennytm
Copy link
Member

kennytm commented Dec 23, 2017

@clarcharr libcore should not contain any public platform-dependent items (liballoc is also platform-independent at the moment). If we move CStr and std::os::raw out, it's better be an independent libffi crate.

@nodakai
Copy link
Contributor

nodakai commented May 7, 2018

Can we not make a pragmatic compromise of moving the meat of CStr (with c_char replaced by u8) to libcore and retain compatibility by providing a facade with c_char in libstd? I doubt we will ever port Rust to any platforms with CHAR_BIT != 8 (which will still be possible with a customized libcore,) and all operations provided by the current CStr seem to be indifferent with the possible signedness of c_char.

Cf. https://stackoverflow.com/questions/40575116/ C's char, signed char and unsigned char are one and the same ("character") type in the context of aliasing.

@clarfonthey
Copy link
Contributor Author

Inconsistency I noticed: CStr converts from [u8], which makes it very obvious that we are putting a preference for u8, but it references c_char. I would consider this a bug but I'm not sure if we'd be able to change this, considering how it'd be a breaking change :(

@est31
Copy link
Member

est31 commented Jun 12, 2018

Including CStr in libcore means the target-dependent type c_char will need to be in libcore as well.

Why is that a problem? usize as well as isize are in libcore as well, and both of them are target dependent.

@kennytm
Copy link
Member

kennytm commented Jun 12, 2018

@est31

  1. usize and isize are built in primitives, c_char is just a type alias to u8 or i8 depending on #[cfg]. Moving c_char to libcore represents a change in policy (even encoded in a tidy check), which while is currently happening due to VaList, should still be verified whether it's suitable.

  2. Just because there's some platform-dependent stuff in libcore (usize and atomics) doesn't mean we want more.

@vsiles
Copy link

vsiles commented Jul 6, 2018

In the meantime, is anyone aware of a crate which would do this (provide cstr/cstring for no_std situation) ?

@clarfonthey
Copy link
Contributor Author

clarfonthey commented Jul 6, 2018

Personally I think that the methods involving *const c_char should be removed (i.e. deprecated) in favour of ones that reference *const u8. That way, people who want to cast to *const c_char still can, but we can at least move CStr to core and CString to alloc without the platform-specific types.

@gnzlbg
Copy link
Contributor

gnzlbg commented Nov 6, 2018

We can't expose CStr in libcore. libcore is by definition platform independent, but CStr is a string of C chars, which are by definition platform-dependent types. In C, char is a different type than signed char and unsigned char, and in particular, the signedness of char is implementation defined (platform specific).

What we could do is move CStr to libc, which is IMO where it belongs. libstd can then re-export libc's CStr in std::ffi::, and libc could re-export libstd's CStr when libstd is available (that is, when libc/use_std is enabled). That way both libc::CStr and std::ffi::CStr would be the same type.

The main reason not to move CStr to libc right now is that it is not FFI safe. Until that's fixed, it's probably dangerous to move it to libc since that might encourage people to use it in C FFI and that would be instant undefined behavior.

@cramertj
Copy link
Member

libcore is by definition platform independent

I don't see how this is true-- as pointed out above, libcore contains usize and isize which both vary by target.

@gnzlbg
Copy link
Contributor

gnzlbg commented Aug 29, 2019

I don't see how this is true-- as pointed out above, libcore contains usize and isize which both vary by target.

To be more specific, they vary by target_env (e.g. depending on the C library used by the target). Are there any other things in libcore that depend on this ?

@clarfonthey
Copy link
Contributor Author

@gnzlbg Different question -- considering the way Rust is currently packaged, it's impossible to get libcore separately from libstd; when you download for a target, you download both. Is there a plan to separate out the current notion of "target" to just the underlying CPU architecture and not the operating/build environment?

This basically affects whether this discussion is meaningful in any way.

@gnzlbg
Copy link
Contributor

gnzlbg commented Aug 30, 2019

@gnzlbg Different question -- considering the way Rust is currently packaged, it's impossible to get libcore separately from libstd; when you download for a target, you download both.

Some targets only ship libcore, and some targets do not even ship libcore.

Is there a plan to separate out the current notion of "target" to just the underlying CPU architecture and not the operating/build environment?

There are targets that are independent of that, e.g., wasm32-unknown-unknown.

@clarfonthey
Copy link
Contributor Author

I guess that I'm asking the wrong question-- the point I'm making is that, although there are targets without libstd, there isn't any notion in Rust of compiled code that's independent from its operating environment. Sure, you can specify the environment to be "none" and the resulting bytecode will be environment-agnostic, but there's never the opportunity to link code between different "targets" regardless of whether they share the same architecture. So, yes, while there are targets that ship without libstd, these targets can still have a "different" libcore than the ones that do, regardless of whether the actual contents of these are the same.

I honestly don't see this changing.

Sure, I agree that using libcore shouldn't require linking against libc. But, on targets that want to link with libc, I don't think it's bad that libcore has code to help with that, because the libcore they're using will always match the environment they're in.

The only way that would change if we offered, say, one compiled version of libcore for all of x86_64. Then, the code for interfacing with libc for x86_64-unknown-linux-gnu and x86_64-pc-windows-msvc, for example, could be incorrect. But, with the way that Rust bundles targets right now, this isn't the case.

@gnzlbg
Copy link
Contributor

gnzlbg commented Aug 30, 2019

Sure, you can specify the environment to be "none" and the resulting bytecode will be environment-agnostic, but there's never the opportunity to link code between different "targets" regardless of whether they share the same architecture.

I'm not sure I follow. You can build a static lib of a none target, and link it with a static lib of a non-none target.

But, on targets that want to link with libc, I don't think it's bad that libcore has code to help with that,

If you have a program that needs to link against libc, you can just link the libc crate.


I feel like moving c_void to libcore was, in hindsight, a bad idea. The libc crate lives between libcore and currently liballoc. We have dozens of workarounds to support binaries that link it twice, once via liballoc, and once from crates.io, for very little value.

The reason c_void was moved into libcore was because libstd::c_void uses the liballoc's libc, and this type is different, but otherwise identical, to the libc::c_void type from crates.io. There are other types like this, e.g., thread handles, and one could make the same argument that the right thing for these would be to live in libcore.

It is probably too late to fix this for c_void, but I think the better fix would be to allow people to use the bundled libc without having to enable a nightly feature. This libc would provide c_void, c_int, CStr, etc. So you could build a #[no_std] binary without liballoc, that uses CStr by just writing use libc::CStr.

@stevemk14ebr
Copy link

stevemk14ebr commented Sep 21, 2021

Hello, any news on this? std::ffi:CString still cannot be used in no_std code. Which is kind of funny considering you can make a null terminated string using format!("{}\x00", str), which is arguably alot more complex.

@petrochenkov
Copy link
Contributor

I think at this point target-specific stuff is used in libcore prominently enough to close the debate and choose the alternative that is useful in practice (i.e. moving at least CStr to libcore).

@petrochenkov
Copy link
Contributor

Branch in progress - https://github.com/petrochenkov/rust/tree/cstr.
I've only moved stuff to liballoc yet, not to libcore, but it seems like there are no technical reasons (coherence or something) preventing this issue from being resolved.

@petrochenkov
Copy link
Contributor

Draft PR: #94079.

@bors bors closed this as completed in 1e6fe58 Apr 15, 2022
workingjubilee pushed a commit to tcdi/postgrestd that referenced this issue Sep 15, 2022
library: Move `CStr` to libcore, and `CString` to liballoc

Closes rust-lang/rust#46736

Interesting points:
- Stability:
    - To make `CStr(ing)` from libcore/liballoc unusable without enabling features I had to make these structures unstable, and reexport them from libstd using stable type aliases instead of `pub use` reexports. (Because stability of `use` items is not checked.)
- Relying on target ABI in libcore is ok:
    - rust-lang/rust#94079 (comment)
- `trait CStrExt` (UPDATE: used only in `cfg(bootstrap)` mode, otherwise lang items are used instead)
    - rust-lang/rust#94079 (comment)
- `strlen`
    - rust-lang/rust#94079 (comment)

Otherwise it's just a code move + some minor hackery usual for liballoc in `cfg(test)` mode.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-FFI Area: Foreign function interface (FFI) C-feature-request Category: A feature request, i.e: not implemented / a PR. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

10 participants