-
-
Notifications
You must be signed in to change notification settings - Fork 15k
core: Add core::ffi::c_intptr_t and core::ffi::c_uintptr_t #156626
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -3,6 +3,8 @@ | |||||
| //! This module is intentionally standalone to facilitate parsing when retrieving | ||||||
| //! core C types. | ||||||
|
|
||||||
| use crate::mem::{self}; | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| macro_rules! type_alias { | ||||||
| { | ||||||
| $Docfile:tt, $Alias:ident = $Real:ty; | ||||||
|
|
@@ -174,6 +176,129 @@ pub type c_ptrdiff_t = isize; | |||||
| #[unstable(feature = "c_size_t", issue = "88345")] | ||||||
| pub type c_ssize_t = isize; | ||||||
|
|
||||||
| /// Equivalent to C's `intptr_t` type. | ||||||
| /// | ||||||
| /// This type have the same size with a pointer. The C standard technically only | ||||||
| /// requires that this type be a signed integer type just capable of holding a | ||||||
| /// pointer. | ||||||
| #[unstable(feature = "c_size_t", issue = "88345")] | ||||||
| #[repr(transparent)] | ||||||
| #[derive(Copy, Clone, Debug)] | ||||||
| pub struct c_intptr_t(*const ()); | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this definition could have an incorrect ABI on some targets since some targets require integers to be sign/zero-extended to fill a register depending on the type's signedness, but if pointers are smaller than a register there is no way for rustc to know if it should sign or zero-extend.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, pointers are not ABI-compatible with any integer type.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, so this is a ABI break, c_intptr_t must be a integer after-all, uintptr_t is ABI in-compatiable with *const () for FFI passing? This is solely for FFI usage, not for writing code. does this will affect FFI-parameter passing? @arichardson , It's you suggested
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This type should be defined as a newtype around
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, I see, so for default, c_intptr_t is just a alais of isize? do I need
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah that's a question for t-libs-api. Should
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's probably best to summarize the situation and open question(s) in a t-libs-api ACP. That's how the team will take a look and give feedback on the open question(s).
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree that isize/usize seems like the safer default. Extension behaviour on 32-on-64 ABIs such as x32 or MIPS n32 mean that using pointers as the underlying type could potentially be wrong (I'd need to double check). What I would really like is if this could remain a somewhat opaque struct with .ptr/.integer accessors so that it's clear that this should be used for FFI calls with unclear typing (could be integer or pointer) and is not just an integer type alias. |
||||||
|
|
||||||
| /// Equivalent to C's `uintptr_t` type. | ||||||
| /// | ||||||
| /// This type have the same size with a pointer. The C standard technically only | ||||||
| /// requires that this type be an unsigned integer type just capable of holding | ||||||
| /// a pointer. | ||||||
| #[unstable(feature = "c_size_t", issue = "88345")] | ||||||
| #[repr(transparent)] | ||||||
| #[derive(Copy, Clone, Debug)] | ||||||
| pub struct c_uintptr_t(*const ()); | ||||||
|
|
||||||
| /// Trait for types that can be used to represent C's `intptr_t` and `uintptr_t` types. | ||||||
| /// | ||||||
| /// For handle interchange of rust `pointer` type and C's `intptr_t` and `uintptr_t` types. | ||||||
| #[unstable(feature = "c_size_t", issue = "88345")] | ||||||
| #[rustc_const_unstable(feature = "c_size_t", issue = "88345")] | ||||||
| pub const trait TaggedPointer { | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this trait should probably be sealed |
||||||
| /// Creates a new instance of IntPtr from a pointer. | ||||||
| #[unstable(feature = "c_size_t", issue = "88345")] | ||||||
| fn new(ptr: *const ()) -> Self; | ||||||
| /// Returns the pointer contained in IntPtr. | ||||||
| #[unstable(feature = "c_size_t", issue = "88345")] | ||||||
| fn ptr(&self) -> *const (); | ||||||
| } | ||||||
|
|
||||||
| /// Trait for retrieving the integer representation of a TaggedPointer. | ||||||
| /// | ||||||
| #[unstable(feature = "c_size_t", issue = "88345")] | ||||||
| pub trait IntPtr: TaggedPointer { | ||||||
| /// The integer type that can hold the tagged pointer value. | ||||||
| type Number; | ||||||
|
|
||||||
| /// Returns the integer representation of the pointer contained in IntPtr. | ||||||
| #[unstable(feature = "c_size_t", issue = "88345")] | ||||||
| fn integer(&self) -> Self::Number; | ||||||
| } | ||||||
|
|
||||||
| #[unstable(feature = "c_size_t", issue = "88345")] | ||||||
| #[rustc_const_unstable(feature = "c_size_t", issue = "88345")] | ||||||
| impl const TaggedPointer for c_intptr_t { | ||||||
| fn new(ptr: *const ()) -> Self { | ||||||
| Self(ptr) | ||||||
| } | ||||||
|
|
||||||
| fn ptr(&self) -> *const () { | ||||||
| self.0 | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| #[unstable(feature = "c_size_t", issue = "88345")] | ||||||
| impl IntPtr for c_intptr_t { | ||||||
| type Number = c_intptr_definition::c_intptr_t; | ||||||
|
|
||||||
| fn integer(&self) -> Self::Number { | ||||||
| // A pointer-to-integer transmute currently has exactly the right semantics: it returns the | ||||||
| // integer representing the pointer without exposing the provenance. Note that this is *not* | ||||||
| // a stable guarantee about transmute semantics, it relies on sysroot crates having special status. | ||||||
| // SAFETY: Pointer-to-integer transmutes are valid (if you are okay with losing the | ||||||
| // provenance). | ||||||
| unsafe { mem::transmute(self.0.cast::<()>()) } | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| #[unstable(feature = "c_size_t", issue = "88345")] | ||||||
| #[rustc_const_unstable(feature = "c_size_t", issue = "88345")] | ||||||
| impl const TaggedPointer for c_uintptr_t { | ||||||
| fn new(ptr: *const ()) -> Self { | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would make a lot of sense to add a usize/isize constructor as well that creates a without_provenance pointer. This would make it more ergonomic to call APIs that use something like "valid pointer" or magic integer (e.g. |
||||||
| Self(ptr) | ||||||
| } | ||||||
|
|
||||||
| fn ptr(&self) -> *const () { | ||||||
| self.0 | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| #[unstable(feature = "c_size_t", issue = "88345")] | ||||||
| impl IntPtr for c_uintptr_t { | ||||||
| type Number = c_intptr_definition::c_uintptr_t; | ||||||
|
|
||||||
| fn integer(&self) -> Self::Number { | ||||||
| // A pointer-to-integer transmute currently has exactly the right semantics: it returns the | ||||||
| // integer representing the pointer without exposing the provenance. Note that this is *not* | ||||||
| // a stable guarantee about transmute semantics, it relies on sysroot crates having special status. | ||||||
| // SAFETY: Pointer-to-integer transmutes are valid (if you are okay with losing the | ||||||
| // provenance). | ||||||
| unsafe { mem::transmute(self.0.cast::<()>()) } | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| mod c_intptr_definition { | ||||||
| crate::cfg_select! { | ||||||
| target_pointer_width = "16" => { | ||||||
| pub(super) type c_intptr_t = i16; | ||||||
| pub(super) type c_uintptr_t = u16; | ||||||
| } | ||||||
| target_pointer_width = "32" => { | ||||||
| pub(super) type c_intptr_t = i32; | ||||||
| pub(super) type c_uintptr_t = u32; | ||||||
| } | ||||||
| target_pointer_width = "64" => { | ||||||
| pub(super) type c_intptr_t = i64; | ||||||
| pub(super) type c_uintptr_t = u64; | ||||||
| } | ||||||
| _ => { | ||||||
| /// 128-bit width pointer. | ||||||
| /// | ||||||
| /// The C standard only requires that these types be large enough to hold a pointer, | ||||||
| /// so we'll use the i128/u128 integer types in Rust. | ||||||
| pub(super) type c_intptr_t = i128; | ||||||
| pub(super) type c_uintptr_t = u128; | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| mod c_int_definition { | ||||||
| crate::cfg_select! { | ||||||
| any(target_arch = "avr", target_arch = "msp430") => { | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,2 @@ | ||
| mod cstr; | ||
| mod intptr; |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,23 @@ | ||||||
| #![deny(fuzzy_provenance_casts)] | ||||||
| #![deny(lossy_provenance_casts)] | ||||||
|
|
||||||
| use core::ffi::{IntPtr, TaggedPointer, c_intptr_t, c_uintptr_t}; | ||||||
|
|
||||||
| extern "C" fn c_ffi_function_on_uintptr(v: c_uintptr_t) { | ||||||
| assert_eq!((v.integer() as usize) & 0xFF_usize, 16_usize); | ||||||
| } | ||||||
|
|
||||||
| #[test] | ||||||
| fn test_intptr_unitptr() { | ||||||
| // These types should have the same size as a pointer. | ||||||
| assert_eq!(core::mem::size_of::<c_intptr_t>(), core::mem::size_of::<*const ()>()); | ||||||
| assert_eq!(core::mem::size_of::<c_uintptr_t>(), core::mem::size_of::<*const ()>()); | ||||||
|
|
||||||
| let ptr = core::ptr::with_exposed_provenance(16_usize); | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| let ptr_uintptr_t = c_uintptr_t::new(ptr); | ||||||
| let ptr_back = ptr_uintptr_t.ptr(); | ||||||
| c_ffi_function_on_uintptr(ptr_uintptr_t); | ||||||
| assert_eq!(ptr_back.addr(), 16_usize); | ||||||
| assert_eq!((ptr_uintptr_t.integer() as usize) & 0xFF_usize, 16_usize); | ||||||
| assert_eq!(ptr, ptr_back); | ||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| # `c_size_t` | ||
|
|
||
| The tracking issue for this feature is: [#88345] | ||
|
|
||
| [#88345]: https://github.com/rust-lang/rust/issues/88345 | ||
| ----- | ||
|
|
||
| The `c_size_t` feature allows to enable C FFI types `size_t` `ssize_t` `intptr_t` `uintptr_t` `ptrdiff_t`. | ||
|
|
||
| ## Example | ||
|
|
||
| ```rust | ||
| #![feature(c_size_t)] | ||
|
|
||
| use std::ffi::{TaggedPointer, c_uintptr_t}; | ||
|
|
||
| fn main() { | ||
| let ptr = core::ptr::with_exposed_provenance(16_usize); | ||
| let _ptr_uintptr_t = c_uintptr_t::new(ptr); | ||
| } | ||
| ``` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| #![crate_type = "lib"] | ||
|
|
||
| use std::ffi::{c_intptr_t}; | ||
| //~^ ERROR use of unstable library feature `c_size_t` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| error[E0658]: use of unstable library feature `c_size_t` | ||
| --> $DIR/feature-gate-c-size-t.rs:3:16 | ||
| | | ||
| LL | use std::ffi::{c_intptr_t}; | ||
| | ^^^^^^^^^^ | ||
| | | ||
| = note: see issue #88345 <https://github.com/rust-lang/rust/issues/88345> for more information | ||
| = help: add `#![feature(c_size_t)]` to the crate attributes to enable | ||
| = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date | ||
|
|
||
| error: aborting due to 1 previous error | ||
|
|
||
| For more information about this error, try `rustc --explain E0658`. |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if this is a library feature, afaik it doesn't need to be added here
View changes since the review