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

[WIP] Enable va_arg for raw pointers to unsized types #61126

Closed

Conversation

ahomescu
Copy link
Contributor

@ahomescu ahomescu commented May 24, 2019

This patch implements VaArgSafe for raw pointers to unsized types, which lets users call VaList::arg for such pointers. Everything else in libcore uses T: ?Sized for raw pointers, so VaList should too, and we already ran into a case where we could use this for C2Rust.

r? @joshtriplett
cc @dlrobertson

@rust-highfive
Copy link
Collaborator

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @joshtriplett (or someone else) soon.

If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes.

Please see the contribution instructions for more information.

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label May 24, 2019
@dlrobertson
Copy link
Contributor

Good catch. Could you add a ui test for this?

@ahomescu
Copy link
Contributor Author

ahomescu commented May 24, 2019

Could you add a ui test for this?

Would src/test/ui/c-variadic be the place for that? Edit: most of the files in that directory seem to check for errors.

@ahomescu ahomescu force-pushed the vaargsafe_unsized_pointers branch from 431c65a to 29f4ad4 Compare May 24, 2019 21:18
@ahomescu
Copy link
Contributor Author

I added a "pointer to foreign type" test to checkrust.rs.

@ghost
Copy link

ghost commented May 25, 2019

Wouldn't this would make ap.arg::<*const [u8]>() legal? Isn't that bad?

@joshtriplett
Copy link
Member

joshtriplett commented May 25, 2019 via email

@ghost
Copy link

ghost commented May 25, 2019

*const [u8] isn't just a pointer though, it's a pointer and a length.

@ahomescu
Copy link
Contributor Author

Wouldn't this would make ap.arg::<*const [u8]>() legal? Isn't that bad?

Right, *const [u8] is a fat pointer, which shouldn't be legal for arg. I'm not sure how to implement this additional restriction, if it can even be done.

Pointers-to-slices and pointers-to-traits are currently the only 2 kinds of fat pointers in Rust, afaik.

@ahomescu
Copy link
Contributor Author

ahomescu commented Jun 3, 2019

My latest update is that I have an idea how to fix this using auto traits (basically making VaArgSafe an auto trait), but I have to do some experiments to see if it works.

@ahomescu
Copy link
Contributor Author

ahomescu commented Jun 4, 2019

After looking into auto traits for a bit, I came to the conclusion that VaArgSafe should probably be an auto trait, with the following consequences:

  • Support for negative implementations, which would let us disable it for slices and/or pointers to slices, e.g., impl<T> !VaArgSafe for *const [T]
  • Implicit support for calling VaList::arg on structures. I originally thought C doesn't support this either, but it turns out that both gcc and clang do support this.
  • Support for calling VaList::arg on unions, enums, Rust tuples, closures and other Rust-specific data types. These ideally wouldn't be allowed, but I haven't been able to figure out how to disable them.

The other kind of fat pointers in Rust are pointers-to-traits, i.e., *const dyn Foo, and I'm not sure how to disable the auto trait for those.

@ahomescu ahomescu changed the title Enable va_arg for raw pointers to unsized types [WIP] Enable va_arg for raw pointers to unsized types Jun 4, 2019
@ahomescu ahomescu force-pushed the vaargsafe_unsized_pointers branch from 29f4ad4 to 0fb85ef Compare June 4, 2019 22:52
@Mark-Simulacrum Mark-Simulacrum added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jul 9, 2019
@dlrobertson
Copy link
Contributor

@ahomescu does this enable the use of VaList::arg with aggregate types? Also how would this work with #62207?

@ahomescu
Copy link
Contributor Author

does this enable the use of VaList::arg with aggregate types?

It actually does, recursively (if all members of the aggregate implement the trait, then the aggregate does too). However, it still doesn't the original problem of allowing fat pointers.

@ahomescu
Copy link
Contributor Author

Also how would this work with #62207?

Adding a function to VaArgSafe precludes making it an auto-trait, but maybe we could solve that by splitting it into 2 traits: the auto VaArgSafe and the actual VaArgImpl.

@dlrobertson
Copy link
Contributor

Adding a function to VaArgSafe precludes making it an auto-trait, but maybe we could solve that by splitting it into 2 traits: the auto VaArgSafe and the actual VaArgImpl.

that seems reasonable

It actually does, recursively

AFAIK I hit some strange errors on windows with aggregate types. If we use auto trait we'd want to start testing aggregate types, not sure if it works now or not.

@rholderfield
Copy link

ping from triage... @ahomescu thank you for your time, can you please provide a status?

@ahomescu
Copy link
Contributor Author

@rholderfield This is blocked until I figure out a way to disable the VaArgSafe trait for pointers to DSTs, e.g., *const [u8] mentioned above by @whataloadofwhat. AFAIK, the language doesn't currently have a way to disable marker traits for fat pointers and references.

The change from a regular trait to an auto trait also enables VaArgSafe automatically for structures. If that's desirable, then the PR could go in as is, and we solve the DST issue later.
I'll defer to @joshtriplett and @dlrobertson on this.

@ahomescu
Copy link
Contributor Author

ahomescu commented Aug 2, 2019

This RFC could help us, since it would let us implement VaArgSafe only on ?Sized + Thin pointers.

@hdhoang hdhoang added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Aug 9, 2019
@hdhoang
Copy link
Contributor

hdhoang commented Aug 9, 2019

ping from triage @joshtriplett and @dlrobertson, could you comment on the author's concern above?

@JohnCSimon
Copy link
Member

JohnCSimon commented Aug 17, 2019

pinging agan from triage @joshtriplett and @dlrobertson @ahomescu

could you comment on the author's concern above?

@dlrobertson
Copy link
Contributor

This RFC could help us, since it would let us implement VaArgSafe only on ?Sized + Thin pointers.

Yeah RFC 2580 would be perfect for resolving this issue.

@joelpalmer joelpalmer removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Aug 26, 2019
@ahomescu
Copy link
Contributor Author

ahomescu commented Sep 4, 2019

I added a source code comment on RFC 2580. In the meantime, we could either wait for that to be implemented, or keep working on this PR as-is.

@ahomescu ahomescu changed the title [WIP] Enable va_arg for raw pointers to unsized types [WIP] Enable va_arg for raw pointers to unsized types and make VaArgSafe an auto trait Sep 4, 2019
@ahomescu ahomescu force-pushed the vaargsafe_unsized_pointers branch from 138f3bb to 74e1455 Compare September 4, 2019 18:04
@ahomescu ahomescu force-pushed the vaargsafe_unsized_pointers branch from 74e1455 to 0ff1661 Compare September 4, 2019 18:59
@ahomescu ahomescu changed the title [WIP] Enable va_arg for raw pointers to unsized types and make VaArgSafe an auto trait [WIP] Enable va_arg for raw pointers to unsized types Sep 4, 2019
@ahomescu
Copy link
Contributor Author

ahomescu commented Sep 4, 2019

I decided to submit a separate PR for the auto-trait along with more tests, so I removed it from this one.

The fix for the *const [u8] issue is blocked on RFC 2580, but everything else works.

@joshtriplett Do you want to approve this PR for now (and fix the issue later), or wait?

@joshtriplett
Copy link
Member

@ahomescu So the current state is that you can't have pointers to unsized types at all (and thus can't accidentally treat a non-thin pointer as FFI-safe/va_arg-safe), and this PR would change that so that you can have pointers to unsized types (which would allow valid things as well as invalid things)? Or have I misunderstood?

@ahomescu
Copy link
Contributor Author

ahomescu commented Sep 9, 2019

@ahomescu So the current state is that you can't have pointers to unsized types at all (and thus can't accidentally treat a non-thin pointer as FFI-safe/va_arg-safe), and this PR would change that so that you can have pointers to unsized types (which would allow valid things as well as invalid things)? Or have I misunderstood?

That basically covers it. The original motivation was to enable VaArgSafe for pointers to opaque FFI (extern) types, which are thin pointers. Once RFC 2580 is implemented, we can actually do that.

@joshtriplett
Copy link
Member

@ahomescu It's not clear to me that we need all of RFC 2580; don't we just want to say that thin pointers are FFI-safe and non-thin pointers aren't?

Also, I don't think we should enable something that makes it easy for people to do the wrong thing here, if we have a means of distinguishing the cases instead and only allowing thin pointers.

@ahomescu
Copy link
Contributor Author

ahomescu commented Sep 9, 2019

don't we just want to say that thin pointers are FFI-safe and non-thin pointers aren't?

Do you mean for improper_ctypes? That's an interesting idea, I'm not sure how that interacts with VaListImpl::arg(). The context here is that we want to allow someone to do ap.arg::<*const Foo>() for an opaque type Foo. Would improper_ctypes even check this?

Edit: Alternatively, it would be great to somehow say "VaArgSafe is only implemented for FFI-safe types" or something similar for VaListImpl::arg.

@joshtriplett
Copy link
Member

joshtriplett commented Sep 9, 2019 via email

@ahomescu
Copy link
Contributor Author

ahomescu commented Sep 9, 2019

@joshtriplett I checked the implementation for improper_ctypes, and it's just a lint that checks that the input and output types for each foreign function are FFI-safe, but with its own implementation of whether each type is FFI-safe.

What I could try to do is replace VaArgSafe with a FfiSafe trait that the compiler auto-magically implements for all FFI-safe types (kinda like Sized), using the implementation from the lint. VaListImpl::arg() would then be implemented for FfiSafe, which would cover the opaque type case and many more.
However, this would turn FfiSafe into a magic trait, is that desirable? Also, is this new trait something that would be useful for other users?

@joshtriplett
Copy link
Member

joshtriplett commented Sep 9, 2019 via email

@ahomescu
Copy link
Contributor Author

@joshtriplett @dlrobertson I discovered something interesting: some of the FFI-unsafe types are not supported by the backend anyway, I added a new UI test with the following:

pub unsafe extern "C" fn vararg_unsafe_types(_: usize, mut ap: ...) {
    let _ = ap.arg::<*const str>();
    let _ = ap.arg::<*const [u8]>();
}

and got an ICE when running the test:

error: internal compiler error: src/librustc_codegen_llvm/intrinsic.rs:178: the va_arg intrinsic does not work with non-scalar types

I've also been looking into the implementation of the improper_ctypes lint, I'm starting to think I might be able to modify it to check the self argument of VaListImpl::arg() for FFI-safety.

@dlrobertson
Copy link
Contributor

That is an interesting ICE. You should post an issue for it. I wonder what the values Abi is if it isn't Scalar?

@bjorn3
Copy link
Member

bjorn3 commented Sep 12, 2019

@dlrobertson It should be ScalarPair, as they are fat pointers.

@hdhoang
Copy link
Contributor

hdhoang commented Sep 20, 2019

ping from triage @ahomescu, any update on this PR or the ICE above?

@ahomescu
Copy link
Contributor Author

@dlrobertson @bjorn3 That ICE only occurs if I enable VaArgSafe for fat pointers, and it makes sense because va_arg isn't implemented in the backend for ScalarPair. rustc on master doesn't get that ICE because you can't read a fat pointer through VaListImpl::arg().

@hdhoang I've looked into possible ways to implement VaArgSafe exclusively for FFI-safe types, and can't see a simple and clean way to do it. I'd be OK with closing this PR for now. I might revisit it later when RFC 2580 goes in.

@JohnCSimon
Copy link
Member

Ping from triage:
@ahomescu Sorry, I can't tell if the status of RFC 2580... what would you like to do with this PR?
Thanks

@ahomescu
Copy link
Contributor Author

@JohnCSimon I'm fine with closing it for now.

@Dylan-DPC-zz
Copy link

Closing this due to inactivity. Thanks for making the effort to contribute and when you want to work on this, you can make a new PR.

@Dylan-DPC-zz Dylan-DPC-zz added S-inactive Status: Inactive and waiting on the author. This is often applied to closed PRs. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Oct 4, 2019
@workingjubilee workingjubilee added the F-c_variadic `#![feature(c_variadic)]` label Jun 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
F-c_variadic `#![feature(c_variadic)]` S-inactive Status: Inactive and waiting on the author. This is often applied to closed PRs.
Projects
None yet
Development

Successfully merging this pull request may close these issues.