-
Notifications
You must be signed in to change notification settings - Fork 13k
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
add wrapping_offset_from which allows wrapping but still requires ptrs to be for the same allocation #112837
Closed
Closed
add wrapping_offset_from which allows wrapping but still requires ptrs to be for the same allocation #112837
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -605,7 +605,9 @@ impl<T: ?Sized> *const T { | |
/// Calculates the distance between two pointers. The returned value is in | ||
/// units of T: the distance in bytes divided by `mem::size_of::<T>()`. | ||
/// | ||
/// This function is the inverse of [`offset`]. | ||
/// This function is the inverse of [`offset`]: it is valid to call if and only if | ||
/// `self` could have been computed as `origin.offset(n)` for some `n`, and it will | ||
/// then return that `n`. | ||
/// | ||
/// [`offset`]: #method.offset | ||
/// | ||
|
@@ -644,6 +646,12 @@ impl<T: ?Sized> *const T { | |
/// (Note that [`offset`] and [`add`] also have a similar limitation and hence cannot be used on | ||
/// such large allocations either.) | ||
/// | ||
/// The requirement for pointers to be derived from the same allocated object is primarily | ||
/// needed for `const`-compatibility: at compile-time, pointers into *different* allocated | ||
/// object do not have a known distance to each other. However, the requirement also exists at | ||
/// runtime, and may be exploited by optimizations. You can use `(self as usize).sub(origin as | ||
/// usize) / mem::size_of::<T>()` to avoid this requirement. | ||
/// | ||
/// [`add`]: #method.add | ||
/// [allocated object]: crate::ptr#allocated-object | ||
/// | ||
|
@@ -701,7 +709,7 @@ impl<T: ?Sized> *const T { | |
/// units of **bytes**. | ||
/// | ||
/// This is purely a convenience for casting to a `u8` pointer and | ||
/// using [offset_from][pointer::offset_from] on it. See that method for | ||
/// using [`offset_from`][pointer::offset_from] on it. See that method for | ||
/// documentation and safety requirements. | ||
/// | ||
/// For non-`Sized` pointees this operation considers only the data pointers, | ||
|
@@ -799,6 +807,108 @@ impl<T: ?Sized> *const T { | |
unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) } | ||
} | ||
|
||
/// Calculates the distance between two pointers using wrapping arithmetic. The returned value | ||
/// is in units of T: the distance in bytes divided by `mem::size_of::<T>()`. | ||
/// | ||
/// This function is the inverse of [`wrapping_offset`]: it is valid to call if and only if | ||
/// `self` could have been computed as `origin.wrapping_offset(n)` for some `n`, and it will | ||
/// then return that `n`. | ||
/// | ||
/// [`wrapping_offset`]: #method.wrapping_offset | ||
/// | ||
/// # Safety | ||
/// | ||
/// If any of the following conditions are violated, the result is Undefined | ||
/// Behavior: | ||
/// | ||
/// * Both pointers must be *derived from* a pointer to the same [allocated object]. | ||
/// (See below for an example.) | ||
/// | ||
/// * The distance between the pointers, in bytes, must be an exact multiple | ||
/// of the size of `T`. | ||
/// | ||
/// Unlike [`offset_from`][pointer::offset_from], this method does *not* require the pointers to | ||
/// be in-bounds of the object they are derived from, nor does it impose any restrictions | ||
/// regarding the maximum distance or wrapping around the address space. | ||
/// | ||
/// The requirement for pointers to be derived from the same allocated object is primarily | ||
/// needed for `const`-compatibility: at compile-time, pointers into *different* allocated | ||
/// object do not have a known distance to each other. However, the requirement also exists at | ||
/// runtime, and may be exploited by optimizations. You can use `(self as usize).sub(origin as | ||
/// usize) / mem::size_of::<T>()` to avoid this requirement. | ||
/// | ||
/// [allocated object]: crate::ptr#allocated-object | ||
/// | ||
/// # Panics | ||
/// | ||
/// This function panics if `T` is a Zero-Sized Type ("ZST"). | ||
/// | ||
/// # Examples | ||
/// | ||
/// Basic usage: | ||
/// | ||
/// ``` | ||
/// #![feature(ptr_wrapping_offset_from)] | ||
/// let a = [0; 2]; | ||
/// let ptr1: *const i32 = &a[1]; | ||
/// let ptr2: *const i32 = a.as_ptr().wrapping_offset(3); // out-of-bounds! | ||
/// unsafe { | ||
/// assert_eq!(ptr2.wrapping_offset_from(ptr1), 2); | ||
/// assert_eq!(ptr1.wrapping_offset_from(ptr2), -2); | ||
/// assert_eq!(ptr1.wrapping_offset(2), ptr2); | ||
/// assert_eq!(ptr2.wrapping_offset(-2), ptr1); | ||
/// } | ||
/// ``` | ||
/// | ||
/// *Incorrect* usage: | ||
/// | ||
/// ```rust,no_run | ||
/// #![feature(ptr_wrapping_offset_from)] | ||
/// let ptr1 = Box::into_raw(Box::new(0u8)) as *const u8; | ||
/// let ptr2 = Box::into_raw(Box::new(1u8)) as *const u8; | ||
/// let diff = (ptr2 as isize).wrapping_sub(ptr1 as isize); | ||
/// // Make ptr2_other an "alias" of ptr2, but derived from ptr1. | ||
/// let ptr2_other = (ptr1 as *const u8).wrapping_offset(diff); | ||
/// assert_eq!(ptr2 as usize, ptr2_other as usize); | ||
/// // Since ptr2_other and ptr2 are derived from pointers to different objects, | ||
/// // computing their offset is undefined behavior, even though | ||
/// // they point to the same address! | ||
/// unsafe { | ||
/// let zero = ptr2_other.wrapping_offset_from(ptr2); // Undefined Behavior | ||
/// } | ||
/// ``` | ||
#[unstable(feature = "ptr_wrapping_offset_from", issue = "none")] | ||
#[rustc_const_unstable(feature = "ptr_wrapping_offset_from", issue = "none")] | ||
#[inline] | ||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces | ||
#[cfg(not(bootstrap))] | ||
pub const unsafe fn wrapping_offset_from(self, origin: *const T) -> isize | ||
where | ||
T: Sized, | ||
{ | ||
// SAFETY: the caller must uphold the safety contract for `ptr_offset_from`. | ||
unsafe { intrinsics::ptr_wrapping_offset_from(self, origin) } | ||
} | ||
|
||
/// Calculates the distance between two pointers using wrapping arithmetic. The returned value | ||
/// is in units of **bytes**. | ||
/// | ||
/// This is purely a convenience for casting to a `u8` pointer and using | ||
/// [`wrapping_offset_from`][pointer::wrapping_offset_from] on it. See that method for | ||
/// documentation and safety requirements. | ||
/// | ||
/// For non-`Sized` pointees this operation considers only the data pointers, | ||
/// ignoring the metadata. | ||
#[inline(always)] | ||
#[unstable(feature = "ptr_wrapping_offset_from", issue = "none")] | ||
#[rustc_const_unstable(feature = "ptr_wrapping_offset_from", issue = "none")] | ||
Comment on lines
+903
to
+904
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 could be tracked with |
||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces | ||
#[cfg(not(bootstrap))] | ||
pub const unsafe fn wrapping_byte_offset_from<U: ?Sized>(self, origin: *const U) -> isize { | ||
// SAFETY: the caller must uphold the safety contract for `wrapping_offset_from`. | ||
unsafe { self.cast::<u8>().wrapping_offset_from(origin.cast::<u8>()) } | ||
} | ||
|
||
/// Returns whether two pointers are guaranteed to be equal. | ||
/// | ||
/// At runtime this function behaves like `Some(self == other)`. | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
We could also have a
wrapping_sub_ptr
, if there is interest.