Skip to content

Commit 9fdd95f

Browse files
authored
Rollup merge of #80383 - RalfJung:wrapping-ptr-arithmetic, r=dtolnay
clarify wrapping ptr arithmetic docs Fixes #80306 `@steffahn` please let me know if this helps avoid the misunderstanding. :)
2 parents 2987785 + 8543388 commit 9fdd95f

File tree

2 files changed

+112
-72
lines changed

2 files changed

+112
-72
lines changed

library/core/src/ptr/const_ptr.rs

+56-36
Original file line numberDiff line numberDiff line change
@@ -232,23 +232,27 @@ impl<T: ?Sized> *const T {
232232
///
233233
/// # Safety
234234
///
235-
/// The resulting pointer does not need to be in bounds, but it is
236-
/// potentially hazardous to dereference (which requires `unsafe`).
235+
/// This operation itself is always safe, but using the resulting pointer is not.
237236
///
238-
/// In particular, the resulting pointer remains attached to the same allocated
239-
/// object that `self` points to. It may *not* be used to access a
240-
/// different allocated object. Note that in Rust,
241-
/// every (stack-allocated) variable is considered a separate allocated object.
237+
/// The resulting pointer remains attached to the same allocated object that `self` points to.
238+
/// It may *not* be used to access a different allocated object. Note that in Rust, every
239+
/// (stack-allocated) variable is considered a separate allocated object.
242240
///
243-
/// In other words, `x.wrapping_offset((y as usize).wrapping_sub(x as usize) / size_of::<T>())`
244-
/// is *not* the same as `y`, and dereferencing it is undefined behavior
245-
/// unless `x` and `y` point into the same allocated object.
241+
/// In other words, `let z = x.wrapping_offset((y as isize) - (x as isize))` does *not* make `z`
242+
/// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
243+
/// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
244+
/// `x` and `y` point into the same allocated object.
246245
///
247-
/// Compared to [`offset`], this method basically delays the requirement of staying
248-
/// within the same allocated object: [`offset`] is immediate Undefined Behavior when
249-
/// crossing object boundaries; `wrapping_offset` produces a pointer but still leads
250-
/// to Undefined Behavior if that pointer is dereferenced. [`offset`] can be optimized
251-
/// better and is thus preferable in performance-sensitive code.
246+
/// Compared to [`offset`], this method basically delays the requirement of staying within the
247+
/// same allocated object: [`offset`] is immediate Undefined Behavior when crossing object
248+
/// boundaries; `wrapping_offset` produces a pointer but still leads to Undefined Behavior if a
249+
/// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`offset`]
250+
/// can be optimized better and is thus preferable in performance-sensitive code.
251+
///
252+
/// The delayed check only considers the value of the pointer that was dereferenced, not the
253+
/// intermediate values used during the computation of the final result. For example,
254+
/// `x.wrapping_offset(o).wrapping_offset(o.wrapping_neg())` is always the same as `x`. In other
255+
/// words, leaving the allocated object and then re-entering it later is permitted.
252256
///
253257
/// If you need to cross object boundaries, cast the pointer to an integer and
254258
/// do the arithmetic there.
@@ -571,19 +575,27 @@ impl<T: ?Sized> *const T {
571575
///
572576
/// # Safety
573577
///
574-
/// The resulting pointer does not need to be in bounds, but it is
575-
/// potentially hazardous to dereference (which requires `unsafe`).
578+
/// This operation itself is always safe, but using the resulting pointer is not.
579+
///
580+
/// The resulting pointer remains attached to the same allocated object that `self` points to.
581+
/// It may *not* be used to access a different allocated object. Note that in Rust, every
582+
/// (stack-allocated) variable is considered a separate allocated object.
583+
///
584+
/// In other words, `let z = x.wrapping_add((y as usize) - (x as usize))` does *not* make `z`
585+
/// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
586+
/// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
587+
/// `x` and `y` point into the same allocated object.
576588
///
577-
/// In particular, the resulting pointer remains attached to the same allocated
578-
/// object that `self` points to. It may *not* be used to access a
579-
/// different allocated object. Note that in Rust,
580-
/// every (stack-allocated) variable is considered a separate allocated object.
589+
/// Compared to [`add`], this method basically delays the requirement of staying within the
590+
/// same allocated object: [`add`] is immediate Undefined Behavior when crossing object
591+
/// boundaries; `wrapping_add` produces a pointer but still leads to Undefined Behavior if a
592+
/// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`add`]
593+
/// can be optimized better and is thus preferable in performance-sensitive code.
581594
///
582-
/// Compared to [`add`], this method basically delays the requirement of staying
583-
/// within the same allocated object: [`add`] is immediate Undefined Behavior when
584-
/// crossing object boundaries; `wrapping_add` produces a pointer but still leads
585-
/// to Undefined Behavior if that pointer is dereferenced. [`add`] can be optimized
586-
/// better and is thus preferable in performance-sensitive code.
595+
/// The delayed check only considers the value of the pointer that was dereferenced, not the
596+
/// intermediate values used during the computation of the final result. For example,
597+
/// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the
598+
/// allocated object and then re-entering it later is permitted.
587599
///
588600
/// If you need to cross object boundaries, cast the pointer to an integer and
589601
/// do the arithmetic there.
@@ -628,19 +640,27 @@ impl<T: ?Sized> *const T {
628640
///
629641
/// # Safety
630642
///
631-
/// The resulting pointer does not need to be in bounds, but it is
632-
/// potentially hazardous to dereference (which requires `unsafe`).
643+
/// This operation itself is always safe, but using the resulting pointer is not.
644+
///
645+
/// The resulting pointer remains attached to the same allocated object that `self` points to.
646+
/// It may *not* be used to access a different allocated object. Note that in Rust, every
647+
/// (stack-allocated) variable is considered a separate allocated object.
648+
///
649+
/// In other words, `let z = x.wrapping_sub((x as usize) - (y as usize))` does *not* make `z`
650+
/// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
651+
/// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
652+
/// `x` and `y` point into the same allocated object.
633653
///
634-
/// In particular, the resulting pointer remains attached to the same allocated
635-
/// object that `self` points to. It may *not* be used to access a
636-
/// different allocated object. Note that in Rust,
637-
/// every (stack-allocated) variable is considered a separate allocated object.
654+
/// Compared to [`sub`], this method basically delays the requirement of staying within the
655+
/// same allocated object: [`sub`] is immediate Undefined Behavior when crossing object
656+
/// boundaries; `wrapping_sub` produces a pointer but still leads to Undefined Behavior if a
657+
/// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`sub`]
658+
/// can be optimized better and is thus preferable in performance-sensitive code.
638659
///
639-
/// Compared to [`sub`], this method basically delays the requirement of staying
640-
/// within the same allocated object: [`sub`] is immediate Undefined Behavior when
641-
/// crossing object boundaries; `wrapping_sub` produces a pointer but still leads
642-
/// to Undefined Behavior if that pointer is dereferenced. [`sub`] can be optimized
643-
/// better and is thus preferable in performance-sensitive code.
660+
/// The delayed check only considers the value of the pointer that was dereferenced, not the
661+
/// intermediate values used during the computation of the final result. For example,
662+
/// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the
663+
/// allocated object and then re-entering it later is permitted.
644664
///
645665
/// If you need to cross object boundaries, cast the pointer to an integer and
646666
/// do the arithmetic there.

library/core/src/ptr/mut_ptr.rs

+56-36
Original file line numberDiff line numberDiff line change
@@ -238,23 +238,27 @@ impl<T: ?Sized> *mut T {
238238
///
239239
/// # Safety
240240
///
241-
/// The resulting pointer does not need to be in bounds, but it is
242-
/// potentially hazardous to dereference (which requires `unsafe`).
241+
/// This operation itself is always safe, but using the resulting pointer is not.
243242
///
244-
/// In particular, the resulting pointer remains attached to the same allocated
245-
/// object that `self` points to. It may *not* be used to access a
246-
/// different allocated object. Note that in Rust,
247-
/// every (stack-allocated) variable is considered a separate allocated object.
243+
/// The resulting pointer remains attached to the same allocated object that `self` points to.
244+
/// It may *not* be used to access a different allocated object. Note that in Rust, every
245+
/// (stack-allocated) variable is considered a separate allocated object.
248246
///
249-
/// In other words, `x.wrapping_offset((y as usize).wrapping_sub(x as usize) / size_of::<T>())`
250-
/// is *not* the same as `y`, and dereferencing it is undefined behavior
251-
/// unless `x` and `y` point into the same allocated object.
247+
/// In other words, `let z = x.wrapping_offset((y as isize) - (x as isize))` does *not* make `z`
248+
/// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
249+
/// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
250+
/// `x` and `y` point into the same allocated object.
252251
///
253-
/// Compared to [`offset`], this method basically delays the requirement of staying
254-
/// within the same allocated object: [`offset`] is immediate Undefined Behavior when
255-
/// crossing object boundaries; `wrapping_offset` produces a pointer but still leads
256-
/// to Undefined Behavior if that pointer is dereferenced. [`offset`] can be optimized
257-
/// better and is thus preferable in performance-sensitive code.
252+
/// Compared to [`offset`], this method basically delays the requirement of staying within the
253+
/// same allocated object: [`offset`] is immediate Undefined Behavior when crossing object
254+
/// boundaries; `wrapping_offset` produces a pointer but still leads to Undefined Behavior if a
255+
/// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`offset`]
256+
/// can be optimized better and is thus preferable in performance-sensitive code.
257+
///
258+
/// The delayed check only considers the value of the pointer that was dereferenced, not the
259+
/// intermediate values used during the computation of the final result. For example,
260+
/// `x.wrapping_offset(o).wrapping_offset(o.wrapping_neg())` is always the same as `x`. In other
261+
/// words, leaving the allocated object and then re-entering it later is permitted.
258262
///
259263
/// If you need to cross object boundaries, cast the pointer to an integer and
260264
/// do the arithmetic there.
@@ -678,19 +682,27 @@ impl<T: ?Sized> *mut T {
678682
///
679683
/// # Safety
680684
///
681-
/// The resulting pointer does not need to be in bounds, but it is
682-
/// potentially hazardous to dereference (which requires `unsafe`).
685+
/// This operation itself is always safe, but using the resulting pointer is not.
686+
///
687+
/// The resulting pointer remains attached to the same allocated object that `self` points to.
688+
/// It may *not* be used to access a different allocated object. Note that in Rust, every
689+
/// (stack-allocated) variable is considered a separate allocated object.
690+
///
691+
/// In other words, `let z = x.wrapping_add((y as usize) - (x as usize))` does *not* make `z`
692+
/// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
693+
/// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
694+
/// `x` and `y` point into the same allocated object.
683695
///
684-
/// In particular, the resulting pointer remains attached to the same allocated
685-
/// object that `self` points to. It may *not* be used to access a
686-
/// different allocated object. Note that in Rust,
687-
/// every (stack-allocated) variable is considered a separate allocated object.
696+
/// Compared to [`add`], this method basically delays the requirement of staying within the
697+
/// same allocated object: [`add`] is immediate Undefined Behavior when crossing object
698+
/// boundaries; `wrapping_add` produces a pointer but still leads to Undefined Behavior if a
699+
/// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`add`]
700+
/// can be optimized better and is thus preferable in performance-sensitive code.
688701
///
689-
/// Compared to [`add`], this method basically delays the requirement of staying
690-
/// within the same allocated object: [`add`] is immediate Undefined Behavior when
691-
/// crossing object boundaries; `wrapping_add` produces a pointer but still leads
692-
/// to Undefined Behavior if that pointer is dereferenced. [`add`] can be optimized
693-
/// better and is thus preferable in performance-sensitive code.
702+
/// The delayed check only considers the value of the pointer that was dereferenced, not the
703+
/// intermediate values used during the computation of the final result. For example,
704+
/// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the
705+
/// allocated object and then re-entering it later is permitted.
694706
///
695707
/// If you need to cross object boundaries, cast the pointer to an integer and
696708
/// do the arithmetic there.
@@ -735,19 +747,27 @@ impl<T: ?Sized> *mut T {
735747
///
736748
/// # Safety
737749
///
738-
/// The resulting pointer does not need to be in bounds, but it is
739-
/// potentially hazardous to dereference (which requires `unsafe`).
750+
/// This operation itself is always safe, but using the resulting pointer is not.
751+
///
752+
/// The resulting pointer remains attached to the same allocated object that `self` points to.
753+
/// It may *not* be used to access a different allocated object. Note that in Rust, every
754+
/// (stack-allocated) variable is considered a separate allocated object.
755+
///
756+
/// In other words, `let z = x.wrapping_sub((x as usize) - (y as usize))` does *not* make `z`
757+
/// the same as `y` even if we assume `T` has size `1` and there is no overflow: `z` is still
758+
/// attached to the object `x` is attached to, and dereferencing it is Undefined Behavior unless
759+
/// `x` and `y` point into the same allocated object.
740760
///
741-
/// In particular, the resulting pointer remains attached to the same allocated
742-
/// object that `self` points to. It may *not* be used to access a
743-
/// different allocated object. Note that in Rust,
744-
/// every (stack-allocated) variable is considered a separate allocated object.
761+
/// Compared to [`sub`], this method basically delays the requirement of staying within the
762+
/// same allocated object: [`sub`] is immediate Undefined Behavior when crossing object
763+
/// boundaries; `wrapping_sub` produces a pointer but still leads to Undefined Behavior if a
764+
/// pointer is dereferenced when it is out-of-bounds of the object it is attached to. [`sub`]
765+
/// can be optimized better and is thus preferable in performance-sensitive code.
745766
///
746-
/// Compared to [`sub`], this method basically delays the requirement of staying
747-
/// within the same allocated object: [`sub`] is immediate Undefined Behavior when
748-
/// crossing object boundaries; `wrapping_sub` produces a pointer but still leads
749-
/// to Undefined Behavior if that pointer is dereferenced. [`sub`] can be optimized
750-
/// better and is thus preferable in performance-sensitive code.
767+
/// The delayed check only considers the value of the pointer that was dereferenced, not the
768+
/// intermediate values used during the computation of the final result. For example,
769+
/// `x.wrapping_add(o).wrapping_sub(o)` is always the same as `x`. In other words, leaving the
770+
/// allocated object and then re-entering it later is permitted.
751771
///
752772
/// If you need to cross object boundaries, cast the pointer to an integer and
753773
/// do the arithmetic there.

0 commit comments

Comments
 (0)