Rollup merge of #131339 - HeroicKatora:set_ptr_value-documentation, r=Mark-Simulacrum

Expand set_ptr_value / with_metadata_of docs

In preparation of a potential FCP, intends to clean up and expand the documentation of this operation.

Rewrite these blobs to explicitly mention the case of a sized operand. The previous made that seem wrong instead of emphasizing it is nothing but a simple cast. Instead, the explanation now emphasizes that the address portion of the argument, together with its provenance, is discarded which previously had to be inferred by the reader. Then an example demonstrates a simple line of incorrect usage based on this idea of provenance.

Tracking issue: https://github.com/rust-lang/rust/issues/75091
This commit is contained in:
Matthias Krüger 2024-10-15 05:11:37 +02:00 committed by GitHub
commit 09103f2617
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 61 additions and 20 deletions

View File

@ -63,21 +63,22 @@ pub const fn cast<U>(self) -> *const U {
self as _
}
/// Uses the pointer value in a new pointer of another type.
/// Uses the address value in a new pointer of another type.
///
/// In case `meta` is a (fat) pointer to an unsized type, this operation
/// will ignore the pointer part, whereas for (thin) pointers to sized
/// types, this has the same effect as a simple cast.
/// This operation will ignore the address part of its `meta` operand and discard existing
/// metadata of `self`. For pointers to a sized types (thin pointers), this has the same effect
/// as a simple cast. For pointers to an unsized type (fat pointers) this recombines the address
/// with new metadata such as slice lengths or `dyn`-vtable.
///
/// The resulting pointer will have provenance of `self`, i.e., for a fat
/// pointer, this operation is semantically the same as creating a new
/// fat pointer with the data pointer value of `self` but the metadata of
/// `meta`.
/// The resulting pointer will have provenance of `self`. This operation is semantically the
/// same as creating a new pointer with the data pointer value of `self` but the metadata of
/// `meta`, being fat or thin depending on the `meta` operand.
///
/// # Examples
///
/// This function is primarily useful for allowing byte-wise pointer
/// arithmetic on potentially fat pointers:
/// This function is primarily useful for enabling pointer arithmetic on potentially fat
/// pointers. The pointer is cast to a sized pointee to utilize offset operations and then
/// recombined with its own original metadata.
///
/// ```
/// #![feature(set_ptr_value)]
@ -91,6 +92,26 @@ pub const fn cast<U>(self) -> *const U {
/// println!("{:?}", &*ptr); // will print "3"
/// }
/// ```
///
/// # *Incorrect* usage
///
/// The provenance from pointers is *not* combined. The result must only be used to refer to the
/// address allowed by `self`.
///
/// ```rust,no_run
/// #![feature(set_ptr_value)]
/// let x = 0u32;
/// let y = 1u32;
///
/// let x = (&x) as *const u32;
/// let y = (&y) as *const u32;
///
/// let offset = (x as usize - y as usize) / 4;
/// let bad = x.wrapping_add(offset).with_metadata_of(y);
///
/// // This dereference is UB. The pointer only has provenance for `x` but points to `y`.
/// println!("{:?}", unsafe { &*bad });
/// ```
#[unstable(feature = "set_ptr_value", issue = "75091")]
#[rustc_const_stable(feature = "ptr_metadata_const", since = "CURRENT_RUSTC_VERSION")]
#[must_use = "returns a new pointer rather than modifying its argument"]

View File

@ -45,21 +45,22 @@ pub const fn cast<U>(self) -> *mut U {
self as _
}
/// Uses the pointer value in a new pointer of another type.
/// Uses the address value in a new pointer of another type.
///
/// In case `meta` is a (fat) pointer to an unsized type, this operation
/// will ignore the pointer part, whereas for (thin) pointers to sized
/// types, this has the same effect as a simple cast.
/// This operation will ignore the address part of its `meta` operand and discard existing
/// metadata of `self`. For pointers to a sized types (thin pointers), this has the same effect
/// as a simple cast. For pointers to an unsized type (fat pointers) this recombines the address
/// with new metadata such as slice lengths or `dyn`-vtable.
///
/// The resulting pointer will have provenance of `self`, i.e., for a fat
/// pointer, this operation is semantically the same as creating a new
/// fat pointer with the data pointer value of `self` but the metadata of
/// `meta`.
/// The resulting pointer will have provenance of `self`. This operation is semantically the
/// same as creating a new pointer with the data pointer value of `self` but the metadata of
/// `meta`, being fat or thin depending on the `meta` operand.
///
/// # Examples
///
/// This function is primarily useful for allowing byte-wise pointer
/// arithmetic on potentially fat pointers:
/// This function is primarily useful for enabling pointer arithmetic on potentially fat
/// pointers. The pointer is cast to a sized pointee to utilize offset operations and then
/// recombined with its own original metadata.
///
/// ```
/// #![feature(set_ptr_value)]
@ -73,6 +74,25 @@ pub const fn cast<U>(self) -> *mut U {
/// println!("{:?}", &*ptr); // will print "3"
/// }
/// ```
///
/// # *Incorrect* usage
///
/// The provenance from pointers is *not* combined. The result must only be used to refer to the
/// address allowed by `self`.
///
/// ```rust,no_run
/// #![feature(set_ptr_value)]
/// let mut x = 0u32;
/// let mut y = 1u32;
///
/// let x = (&mut x) as *mut u32;
/// let y = (&mut y) as *mut u32;
///
/// let offset = (x as usize - y as usize) / 4;
/// let bad = x.wrapping_add(offset).with_metadata_of(y);
///
/// // This dereference is UB. The pointer only has provenance for `x` but points to `y`.
/// println!("{:?}", unsafe { &*bad });
#[unstable(feature = "set_ptr_value", issue = "75091")]
#[rustc_const_stable(feature = "ptr_metadata_const", since = "CURRENT_RUSTC_VERSION")]
#[must_use = "returns a new pointer rather than modifying its argument"]