Expand set_ptr_value / with_metadata_of docs

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.
This commit is contained in:
Andreas Molzer 2024-10-06 21:32:04 +02:00
parent f7c8928f03
commit 2bd0d070ed
2 changed files with 61 additions and 20 deletions

View File

@ -63,21 +63,22 @@ impl<T: ?Sized> *const T {
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 thing 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 @@ impl<T: ?Sized> *const T {
/// 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 @@ impl<T: ?Sized> *mut T {
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 thing 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 @@ impl<T: ?Sized> *mut T {
/// 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"]