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

clarify wrapping ptr arithmetic docs #80383

Merged
merged 2 commits into from
Dec 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 56 additions & 36 deletions library/core/src/ptr/const_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,23 +232,27 @@ impl<T: ?Sized> *const T {
///
/// # Safety
///
/// The resulting pointer does not need to be in bounds, but it is
/// potentially hazardous to dereference (which requires `unsafe`).
/// This operation itself is always safe, but using the resulting pointer is not.
///
/// In particular, the resulting pointer remains attached to the same allocated
/// object that `self` points to. It may *not* be used to access a
/// different allocated object. Note that in Rust,
/// every (stack-allocated) variable is considered a separate allocated object.
/// The resulting pointer remains attached to the same allocated object that `self` points to.
/// It may *not* be used to access a different allocated object. Note that in Rust, every
/// (stack-allocated) variable is considered a separate allocated object.
///
/// In other words, `x.wrapping_offset((y as usize).wrapping_sub(x as usize) / size_of::<T>())`
/// is *not* the same as `y`, and dereferencing it is undefined behavior
/// unless `x` and `y` point into the same allocated object.
/// In other words, `let z = x.wrapping_offset((y as isize) - (x as isize))` does *not* make `z`
/// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
/// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
/// `x` and `y` point into the same allocated object.
///
/// Compared to [`offset`], this method basically delays the requirement of staying
/// within the same allocated object: [`offset`] is immediate Undefined Behavior when
/// crossing object boundaries; `wrapping_offset` produces a pointer but still leads
/// to Undefined Behavior if that pointer is dereferenced. [`offset`] can be optimized
/// better and is thus preferable in performance-sensitive code.
/// Compared to [`offset`], this method basically delays the requirement of staying within the
/// same allocated object: [`offset`] is immediate Undefined Behavior when crossing object
/// boundaries; `wrapping_offset` produces a pointer but still leads to Undefined Behavior if a
/// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`offset`]
/// can be optimized better and is thus preferable in performance-sensitive code.
///
/// The delayed check only considers the value of the pointer that was dereferenced, not the
/// intermediate values used during the computation of the final result. For example,
/// `x.wrapping_offset(o).wrapping_offset(o.wrapping_neg())` is always the same as `x`. In other
/// words, leaving the allocated object and then re-entering it later is permitted.
///
/// If you need to cross object boundaries, cast the pointer to an integer and
/// do the arithmetic there.
Expand Down Expand Up @@ -571,19 +575,27 @@ impl<T: ?Sized> *const T {
///
/// # Safety
///
/// The resulting pointer does not need to be in bounds, but it is
/// potentially hazardous to dereference (which requires `unsafe`).
/// This operation itself is always safe, but using the resulting pointer is not.
///
/// The resulting pointer remains attached to the same allocated object that `self` points to.
/// It may *not* be used to access a different allocated object. Note that in Rust, every
/// (stack-allocated) variable is considered a separate allocated object.
///
/// In other words, `let z = x.wrapping_add((y as usize) - (x as usize))` does *not* make `z`
/// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
/// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
/// `x` and `y` point into the same allocated object.
///
/// In particular, the resulting pointer remains attached to the same allocated
/// object that `self` points to. It may *not* be used to access a
/// different allocated object. Note that in Rust,
/// every (stack-allocated) variable is considered a separate allocated object.
/// Compared to [`add`], this method basically delays the requirement of staying within the
/// same allocated object: [`add`] is immediate Undefined Behavior when crossing object
/// boundaries; `wrapping_add` produces a pointer but still leads to Undefined Behavior if a
/// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`add`]
/// can be optimized better and is thus preferable in performance-sensitive code.
///
/// Compared to [`add`], this method basically delays the requirement of staying
/// within the same allocated object: [`add`] is immediate Undefined Behavior when
/// crossing object boundaries; `wrapping_add` produces a pointer but still leads
/// to Undefined Behavior if that pointer is dereferenced. [`add`] can be optimized
/// better and is thus preferable in performance-sensitive code.
/// The delayed check only considers the value of the pointer that was dereferenced, not the
/// intermediate values used during the computation of the final result. For example,
/// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the
/// allocated object and then re-entering it later is permitted.
///
/// If you need to cross object boundaries, cast the pointer to an integer and
/// do the arithmetic there.
Expand Down Expand Up @@ -628,19 +640,27 @@ impl<T: ?Sized> *const T {
///
/// # Safety
///
/// The resulting pointer does not need to be in bounds, but it is
/// potentially hazardous to dereference (which requires `unsafe`).
/// This operation itself is always safe, but using the resulting pointer is not.
///
/// The resulting pointer remains attached to the same allocated object that `self` points to.
/// It may *not* be used to access a different allocated object. Note that in Rust, every
/// (stack-allocated) variable is considered a separate allocated object.
///
/// In other words, `let z = x.wrapping_sub((x as usize) - (y as usize))` does *not* make `z`
/// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
/// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
/// `x` and `y` point into the same allocated object.
///
/// In particular, the resulting pointer remains attached to the same allocated
/// object that `self` points to. It may *not* be used to access a
/// different allocated object. Note that in Rust,
/// every (stack-allocated) variable is considered a separate allocated object.
/// Compared to [`sub`], this method basically delays the requirement of staying within the
/// same allocated object: [`sub`] is immediate Undefined Behavior when crossing object
/// boundaries; `wrapping_sub` produces a pointer but still leads to Undefined Behavior if a
/// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`sub`]
/// can be optimized better and is thus preferable in performance-sensitive code.
///
/// Compared to [`sub`], this method basically delays the requirement of staying
/// within the same allocated object: [`sub`] is immediate Undefined Behavior when
/// crossing object boundaries; `wrapping_sub` produces a pointer but still leads
/// to Undefined Behavior if that pointer is dereferenced. [`sub`] can be optimized
/// better and is thus preferable in performance-sensitive code.
/// The delayed check only considers the value of the pointer that was dereferenced, not the
/// intermediate values used during the computation of the final result. For example,
/// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the
/// allocated object and then re-entering it later is permitted.
///
/// If you need to cross object boundaries, cast the pointer to an integer and
/// do the arithmetic there.
Expand Down
92 changes: 56 additions & 36 deletions library/core/src/ptr/mut_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,23 +238,27 @@ impl<T: ?Sized> *mut T {
///
/// # Safety
///
/// The resulting pointer does not need to be in bounds, but it is
/// potentially hazardous to dereference (which requires `unsafe`).
/// This operation itself is always safe, but using the resulting pointer is not.
///
/// In particular, the resulting pointer remains attached to the same allocated
/// object that `self` points to. It may *not* be used to access a
/// different allocated object. Note that in Rust,
/// every (stack-allocated) variable is considered a separate allocated object.
/// The resulting pointer remains attached to the same allocated object that `self` points to.
/// It may *not* be used to access a different allocated object. Note that in Rust, every
/// (stack-allocated) variable is considered a separate allocated object.
///
/// In other words, `x.wrapping_offset((y as usize).wrapping_sub(x as usize) / size_of::<T>())`
/// is *not* the same as `y`, and dereferencing it is undefined behavior
/// unless `x` and `y` point into the same allocated object.
/// In other words, `let z = x.wrapping_offset((y as isize) - (x as isize))` does *not* make `z`
/// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
/// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
/// `x` and `y` point into the same allocated object.
///
/// Compared to [`offset`], this method basically delays the requirement of staying
/// within the same allocated object: [`offset`] is immediate Undefined Behavior when
/// crossing object boundaries; `wrapping_offset` produces a pointer but still leads
/// to Undefined Behavior if that pointer is dereferenced. [`offset`] can be optimized
/// better and is thus preferable in performance-sensitive code.
/// Compared to [`offset`], this method basically delays the requirement of staying within the
/// same allocated object: [`offset`] is immediate Undefined Behavior when crossing object
/// boundaries; `wrapping_offset` produces a pointer but still leads to Undefined Behavior if a
/// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`offset`]
/// can be optimized better and is thus preferable in performance-sensitive code.
///
/// The delayed check only considers the value of the pointer that was dereferenced, not the
/// intermediate values used during the computation of the final result. For example,
/// `x.wrapping_offset(o).wrapping_offset(o.wrapping_neg())` is always the same as `x`. In other
/// words, leaving the allocated object and then re-entering it later is permitted.
///
/// If you need to cross object boundaries, cast the pointer to an integer and
/// do the arithmetic there.
Expand Down Expand Up @@ -678,19 +682,27 @@ impl<T: ?Sized> *mut T {
///
/// # Safety
///
/// The resulting pointer does not need to be in bounds, but it is
/// potentially hazardous to dereference (which requires `unsafe`).
/// This operation itself is always safe, but using the resulting pointer is not.
///
/// The resulting pointer remains attached to the same allocated object that `self` points to.
/// It may *not* be used to access a different allocated object. Note that in Rust, every
/// (stack-allocated) variable is considered a separate allocated object.
///
/// In other words, `let z = x.wrapping_add((y as usize) - (x as usize))` does *not* make `z`
/// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
/// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
/// `x` and `y` point into the same allocated object.
///
/// In particular, the resulting pointer remains attached to the same allocated
/// object that `self` points to. It may *not* be used to access a
/// different allocated object. Note that in Rust,
/// every (stack-allocated) variable is considered a separate allocated object.
/// Compared to [`add`], this method basically delays the requirement of staying within the
/// same allocated object: [`add`] is immediate Undefined Behavior when crossing object
/// boundaries; `wrapping_add` produces a pointer but still leads to Undefined Behavior if a
/// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`add`]
/// can be optimized better and is thus preferable in performance-sensitive code.
///
/// Compared to [`add`], this method basically delays the requirement of staying
/// within the same allocated object: [`add`] is immediate Undefined Behavior when
/// crossing object boundaries; `wrapping_add` produces a pointer but still leads
/// to Undefined Behavior if that pointer is dereferenced. [`add`] can be optimized
/// better and is thus preferable in performance-sensitive code.
/// The delayed check only considers the value of the pointer that was dereferenced, not the
/// intermediate values used during the computation of the final result. For example,
/// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the
/// allocated object and then re-entering it later is permitted.
///
/// If you need to cross object boundaries, cast the pointer to an integer and
/// do the arithmetic there.
Expand Down Expand Up @@ -735,19 +747,27 @@ impl<T: ?Sized> *mut T {
///
/// # Safety
///
/// The resulting pointer does not need to be in bounds, but it is
/// potentially hazardous to dereference (which requires `unsafe`).
/// This operation itself is always safe, but using the resulting pointer is not.
///
/// The resulting pointer remains attached to the same allocated object that `self` points to.
/// It may *not* be used to access a different allocated object. Note that in Rust, every
/// (stack-allocated) variable is considered a separate allocated object.
///
/// In other words, `let z = x.wrapping_sub((x as usize) - (y as usize))` does *not* make `z`
/// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
/// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
/// `x` and `y` point into the same allocated object.
///
/// In particular, the resulting pointer remains attached to the same allocated
/// object that `self` points to. It may *not* be used to access a
/// different allocated object. Note that in Rust,
/// every (stack-allocated) variable is considered a separate allocated object.
/// Compared to [`sub`], this method basically delays the requirement of staying within the
/// same allocated object: [`sub`] is immediate Undefined Behavior when crossing object
/// boundaries; `wrapping_sub` produces a pointer but still leads to Undefined Behavior if a
/// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`sub`]
/// can be optimized better and is thus preferable in performance-sensitive code.
///
/// Compared to [`sub`], this method basically delays the requirement of staying
/// within the same allocated object: [`sub`] is immediate Undefined Behavior when
/// crossing object boundaries; `wrapping_sub` produces a pointer but still leads
/// to Undefined Behavior if that pointer is dereferenced. [`sub`] can be optimized
/// better and is thus preferable in performance-sensitive code.
/// The delayed check only considers the value of the pointer that was dereferenced, not the
/// intermediate values used during the computation of the final result. For example,
/// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the
/// allocated object and then re-entering it later is permitted.
///
/// If you need to cross object boundaries, cast the pointer to an integer and
/// do the arithmetic there.
Expand Down