diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 43dcc180b86..b9b086db010 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -976,19 +976,15 @@ extern "rust-intrinsic" { /// /// Behavior is undefined if any of the following conditions are violated: /// + /// * `src` must be [valid] for reads of `count * size_of::()` bytes. + /// + /// * `dst` must be [valid] for writes of `count * size_of::()` bytes. + /// /// * Both `src` and `dst` must be properly aligned. /// - /// * `src.offset(i)` must be [valid] for all `i` in `0..count`. In other - /// words, the region of memory which begins at `src` and has a length of - /// `count * size_of::()` bytes must belong to a single, live - /// allocation. - /// - /// * `dst.offset(i)` must be [valid] for all `i` in `0..count`. In other - /// words, the region of memory which begins at `dst` and has a length of - /// `count * size_of::()` bytes must belong to a single, live - /// allocation. - /// - /// * The two regions of memory must *not* overlap. + /// * The region of memory beginning at `src` with a size of `count * + /// size_of::()` bytes must *not* overlap with the region of memory + /// beginning at `dst` with the same size. /// /// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of /// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values @@ -1064,18 +1060,12 @@ extern "rust-intrinsic" { /// /// Behavior is undefined if any of the following conditions are violated: /// + /// * `src` must be [valid] for reads of `count * size_of::()` bytes. + /// + /// * `dst` must be [valid] for writes of `count * size_of::()` bytes. + /// /// * Both `src` and `dst` must be properly aligned. /// - /// * `src.offset(i)` must be [valid] for all `i` in `0..count`. In other - /// words, the region of memory which begins at `src` and has a length of - /// `count * size_of::()` bytes must belong to a single, live - /// allocation. - /// - /// * `dst.offset(i)` must be [valid] for all `i` in `0..count`. In other - /// words, the region of memory which begins at `dst` and has a length of - /// `count * size_of::()` bytes must belong to a single, live - /// allocation. - /// /// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of /// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values /// in the region beginning at `*src` and the region beginning at `*dst` can @@ -1116,12 +1106,9 @@ extern "rust-intrinsic" { /// /// Behavior is undefined if any of the following conditions are violated: /// - /// * `dst` must be properly aligned. + /// * `dst` must be [valid] for writes of `count * size_of::()` bytes. /// - /// * `dst.offset(i)` must be [valid] for all `i` in `0..count`. In other - /// words, the region of memory which begins at `dst` and has a length of - /// `count * size_of::()` bytes must belong to a single, live - /// allocation. + /// * `dst` must be properly aligned. /// /// Additionally, the caller must ensure that writing `count * /// size_of::()` bytes to the given region of memory results in a valid diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 7cbb4462d06..ee209b9ccca 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -19,25 +19,38 @@ //! Many functions in this module take raw pointers as arguments and dereference //! them. For this to be safe, these pointers must be valid. However, because //! rust does not yet have a formal memory model, determining whether an -//! arbitrary pointer is a valid one can be tricky. One thing is certain: -//! creating a raw pointer from a reference (e.g. `&x as *const _`) *always* -//! results in a valid pointer. By exploiting this—and by taking care when -//! using [pointer arithmetic]—users can be confident in the correctness of -//! their unsafe code. +//! arbitrary pointer is valid for a given operation can be tricky. //! -//! For more information on dereferencing raw pointers, see the both the [book] -//! and the section in the reference devoted to [undefined behavior][ub]. +//! There are two types of operations on memory, reads and writes. It is +//! possible for a `*mut` to be valid for one operation and not the other. Since +//! a `*const` can only be read and not written, it has no such ambiguity. For +//! example, a `*mut` is not valid for writes if a a reference exists which +//! [refers to the same memory][aliasing]. Therefore, each function in this +//! module will document which operations must be valid on any `*mut` arguments. +//! +//! Additionally, some functions (e.g. [`copy`]) take a single pointer but +//! operate on many values. In this case, the function will state the size of +//! the operation for which the pointer must be valid. For example, +//! `copy::(&src, &mut dst, 3)` requires `dst` to be valid for writes of +//! `size_of::() * 3` bytes. When the documentation requires that a pointer +//! be valid for an operation but omits the size of that operation, the size is +//! implied to be `size_of::()` bytes. +//! +//! For more information on the safety implications of dereferencing raw +//! pointers, see the both the [book] and the section in the reference devoted +//! to [undefined behavior][ub]. //! //! ## Alignment //! //! Valid pointers are not necessarily properly aligned. However, most functions //! require their arguments to be properly aligned, and will explicitly state -//! this requirement in the `Safety` section. Notable exceptions to this are +//! this requirement in their documentation. Notable exceptions to this are //! [`read_unaligned`] and [`write_unaligned`]. //! -//! [ub]: ../../reference/behavior-considered-undefined.html +//! [aliasing]: ../../nomicon/aliasing.html //! [book]: ../../book/second-edition/ch19-01-unsafe-rust.html#dereferencing-a-raw-pointer -//! [pointer arithmetic]: ../../std/primitive.pointer.html#method.offset +//! [ub]: ../../reference/behavior-considered-undefined.html +//! [`copy`]: ./fn.copy.html //! [`read_unaligned`]: ./fn.read_unaligned.html //! [`write_unaligned`]: ./fn.write_unaligned.html @@ -83,7 +96,7 @@ pub use intrinsics::write_bytes; /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * `to_drop` must be [valid]. +/// * `to_drop` must be [valid] for reads. /// /// * `to_drop` must be properly aligned. /// @@ -178,7 +191,7 @@ pub const fn null_mut() -> *mut T { 0 as *mut T } /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * Both `x` and `y` must be [valid]. +/// * Both `x` and `y` must be [valid] for reads and writes. /// /// * Both `x` and `y` must be properly aligned. /// @@ -240,17 +253,14 @@ pub unsafe fn swap(x: *mut T, y: *mut T) { /// /// Behavior is undefined if any of the following conditions are violated: /// +/// * Both `x` and `y` must be [valid] for reads and writes of `count * +/// size_of::()` bytes. +/// /// * Both `x` and `y` must be properly aligned. /// -/// * `x.offset(i)` must be [valid] for all `i` in `0..count`. In other words, -/// the region of memory which begins at `x` and has a length of `count * -/// size_of::()` bytes must belong to a single, live allocation. -/// -/// * `y.offset(i)` must be [valid] for all `i` in `0..count`. In other words, -/// the region of memory which begins at `y` and has a length of `count * -/// size_of::()` bytes must belong to a single, live allocation. -/// -/// * The two regions of memory must *not* overlap. +/// * The region of memory beginning at `x` with a size of `count * +/// size_of::()` bytes must *not* overlap with the region of memory +/// beginning at `y` with the same size. /// /// [valid]: ../ptr/index.html#safety /// @@ -359,7 +369,7 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * `dest` must be [valid]. +/// * `dest` must be [valid] for writes. /// /// * `dest` must be properly aligned. /// @@ -395,7 +405,7 @@ pub unsafe fn replace(dest: *mut T, mut src: T) -> T { /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * `src` must be [valid]. +/// * `src` must be [valid] for reads. /// /// * `src` must be properly aligned. Use [`read_unaligned`] if this is not the /// case. @@ -508,7 +518,7 @@ pub unsafe fn read(src: *const T) -> T { /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * `src` must be [valid]. +/// * `src` must be [valid] for reads. /// /// Like [`read`], `read_unaligned` creates a bitwise copy of `T`, regardless of /// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the returned @@ -585,7 +595,7 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * `dst` must be [valid]. +/// * `dst` must be [valid] for writes. /// /// * `dst` must be properly aligned. Use [`write_unaligned`] if this is not the /// case. @@ -659,7 +669,7 @@ pub unsafe fn write(dst: *mut T, src: T) { /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * `dst` must be [valid]. +/// * `dst` must be [valid] for writes. /// /// [valid]: ../ptr/index.html#safety /// @@ -734,7 +744,7 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * `src` must be [valid]. +/// * `src` must be [valid] for reads. /// /// * `src` must be properly aligned. /// @@ -809,7 +819,7 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * `dst` must be [valid]. +/// * `dst` must be [valid] for writes. /// /// * `dst` must be properly aligned. ///