From 8b8091d370fa31844d6ed55f4ccdd32e5dbd20f9 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Fri, 6 Apr 2018 00:34:45 -0700 Subject: [PATCH 1/9] Rewrite docs for `std::ptr` - Add links to the GNU libc docs for `memmove`, `memcpy`, and `memset`, as well as internally linking to other functions in `std::ptr` - List sources of UB for all functions. - Add example to `ptr::drop_in_place` and compares it to `ptr::read`. - Add examples which more closely mirror real world uses for the functions in `std::ptr`. Also, move the reimplementation of `mem::swap` to the examples of `ptr::read` and use a more interesting example for `copy_nonoverlapping`. - Change module level description --- src/libcore/intrinsics.rs | 177 +++++++++++++--- src/libcore/ptr.rs | 421 +++++++++++++++++++++++++++++++------- 2 files changed, 496 insertions(+), 102 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 83274682250b0..d6bd2b868554c 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -959,59 +959,134 @@ extern "rust-intrinsic" { /// value is not necessarily valid to be used to actually access memory. pub fn arith_offset(dst: *const T, offset: isize) -> *const T; - /// Copies `count * size_of` bytes from `src` to `dst`. The source - /// and destination may *not* overlap. + /// Copies `count * size_of::()` bytes from `src` to `dst`. The source + /// and destination must *not* overlap. /// - /// `copy_nonoverlapping` is semantically equivalent to C's `memcpy`. + /// For regions of memory which might overlap, use [`copy`] instead. + /// + /// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`]. + /// + /// [`copy`]: ./fn.copy.html + /// [`memcpy`]: https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html#index-memcpy /// /// # Safety /// - /// Beyond requiring that the program must be allowed to access both regions - /// of memory, it is Undefined Behavior for source and destination to - /// overlap. Care must also be taken with the ownership of `src` and - /// `dst`. This method semantically moves the values of `src` into `dst`. - /// However it does not drop the contents of `dst`, or prevent the contents - /// of `src` from being dropped or used. + /// `copy_nonoverlapping` is unsafe because it dereferences a raw pointer. + /// The caller must ensure that `src` points to a valid sequence of type + /// `T`. + /// + /// # [Undefined Behavior] + /// + /// Behavior is undefined if any of the following conditions are violated: + /// + /// * The region of memory which begins at `src` and has a length of + /// `count * size_of::()` bytes must be *both* valid and initialized. + /// + /// * The region of memory which begins at `dst` and has a length of + /// `count * size_of::()` bytes must be valid (but may or may not be + /// initialized). + /// + /// * `src` must be properly aligned. + /// + /// * `dst` must be properly aligned. + /// + /// * The two regions of memory must *not* overlap. + /// + /// Additionally, if `T` is not [`Copy`](../marker/trait.Copy), only the region at `src` *or* the + /// region at `dst` can be used or dropped after calling + /// `copy_nonoverlapping`. `copy_nonoverlapping` creates bitwise copies of + /// `T`, regardless of whether `T: Copy`, which can result in undefined + /// behavior if both copies are used. + /// + /// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// - /// A safe swap function: + /// Manually implement [`Vec::append`]: /// /// ``` - /// use std::mem; /// use std::ptr; /// - /// # #[allow(dead_code)] - /// fn swap(x: &mut T, y: &mut T) { + /// /// Moves all the elements of `src` into `dst`, leaving `src` empty. + /// fn append(dst: &mut Vec, src: &mut Vec) { + /// let src_len = src.len(); + /// let dst_len = dst.len(); + /// + /// // Ensure that `dst` has enough capacity to hold all of `src`. + /// dst.reserve(src_len); + /// /// unsafe { - /// // Give ourselves some scratch space to work with - /// let mut t: T = mem::uninitialized(); + /// // The call to offset is always safe because `Vec` will never + /// // allocate more than `isize::MAX` bytes. + /// let dst = dst.as_mut_ptr().offset(dst_len as isize); + /// let src = src.as_ptr(); + /// + /// // The two regions cannot overlap becuase mutable references do + /// // not alias, and two different vectors cannot own the same + /// // memory. + /// ptr::copy_nonoverlapping(src, dst, src_len); + /// } /// - /// // Perform the swap, `&mut` pointers never alias - /// ptr::copy_nonoverlapping(x, &mut t, 1); - /// ptr::copy_nonoverlapping(y, x, 1); - /// ptr::copy_nonoverlapping(&t, y, 1); + /// unsafe { + /// // Truncate `src` without dropping its contents. + /// src.set_len(0); /// - /// // y and t now point to the same thing, but we need to completely forget `t` - /// // because it's no longer relevant. - /// mem::forget(t); + /// // Notify `dst` that it now holds the contents of `src`. + /// dst.set_len(dst_len + src_len); /// } /// } + /// + /// let mut a = vec!['r']; + /// let mut b = vec!['u', 's', 't']; + /// + /// append(&mut a, &mut b); + /// + /// assert_eq!(a, &['r', 'u', 's', 't']); + /// assert!(b.is_empty()); /// ``` + /// + /// [`Vec::append()`]: ../vec/struct.Vec.html#method.append #[stable(feature = "rust1", since = "1.0.0")] pub fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); - /// Copies `count * size_of` bytes from `src` to `dst`. The source + /// Copies `count * size_of::()` bytes from `src` to `dst`. The source /// and destination may overlap. /// - /// `copy` is semantically equivalent to C's `memmove`. + /// If the source and destination will *never* overlap, + /// [`copy_nonoverlapping`] can be used instead. + /// + /// `copy` is semantically equivalent to C's [`memmove`]. + /// + /// [`copy_nonoverlapping`]: ./fn.copy_nonoverlapping.html + /// [`memmove`]: https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html#index-memmove /// /// # Safety /// - /// Care must be taken with the ownership of `src` and `dst`. - /// This method semantically moves the values of `src` into `dst`. - /// However it does not drop the contents of `dst`, or prevent the contents of `src` - /// from being dropped or used. + /// `copy` is unsafe because it dereferences a raw pointer. The caller must + /// ensure that `src` points to a valid sequence of type `T`. + /// + /// # [Undefined Behavior] + /// + /// Behavior is undefined if any of the following conditions are violated: + /// + /// * The region of memory which begins at `src` and has a length of + /// `count * size_of::()` bytes must be *both* valid and initialized. + /// + /// * The region of memory which begins at `dst` and has a length of + /// `count * size_of::()` bytes must be valid (but may or may not be + /// initialized). + /// + /// * `src` must be properly aligned. + /// + /// * `dst` must be properly aligned. + /// + /// Additionally, if `T` is not [`Copy`], only the region at `src` *or* the + /// region at `dst` can be used or dropped after calling `copy`. `copy` + /// creates bitwise copies of `T`, regardless of whether `T: Copy`, which + /// can result in undefined behavior if both copies are used. + /// + /// [`Copy`]: ../marker/trait.Copy.html + /// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// @@ -1028,15 +1103,39 @@ extern "rust-intrinsic" { /// dst /// } /// ``` - /// #[stable(feature = "rust1", since = "1.0.0")] pub fn copy(src: *const T, dst: *mut T, count: usize); - /// Invokes memset on the specified pointer, setting `count * size_of::()` - /// bytes of memory starting at `dst` to `val`. + /// Sets `count * size_of::()` bytes of memory starting at `dst` to + /// `val`. + /// + /// `write_bytes` is semantically equivalent to C's [`memset`]. + /// + /// [`memset`]: https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html#index-memset + /// + /// # Safety + /// + /// `write_bytes` is unsafe because it dereferences a raw pointer. The + /// caller must ensure that the poiinter points to a valid value of type `T`. + /// + /// # [Undefined Behavior] + /// + /// Behavior is undefined if any of the following conditions are violated: + /// + /// * The region of memory which begins at `dst` and has a length of + /// `count` bytes must be valid. + /// + /// * `dst` must be properly aligned. + /// + /// Additionally, the caller must ensure that writing `count` bytes to the + /// given region of memory results in a valid value of `T`. Creating an + /// invalid value of `T` can result in undefined behavior. An example is + /// provided below. /// /// # Examples /// + /// Basic usage: + /// /// ``` /// use std::ptr; /// @@ -1047,6 +1146,22 @@ extern "rust-intrinsic" { /// } /// assert_eq!(vec, [b'a', b'a', 0, 0]); /// ``` + /// + /// Creating an invalid value: + /// + /// ```ignore + /// use std::{mem, ptr}; + /// + /// let mut v = Box::new(0i32); + /// + /// unsafe { + /// // Leaks the previously held value by overwriting the `Box` with + /// // a null pointer. + /// ptr::write_bytes(&mut v, 0, mem::size_of::>()); + /// } + /// + /// // At this point, using or dropping `v` results in undefined behavior. + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn write_bytes(dst: *mut T, val: u8, count: usize); diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 5a54de06b5ef2..98d5030477b51 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -10,7 +10,7 @@ // FIXME: talk about offset, copy_memory, copy_nonoverlapping_memory -//! Raw, unsafe pointers, `*const T`, and `*mut T`. +//! Manually manage memory through raw, unsafe pointers. //! //! *[See also the pointer primitive types](../../std/primitive.pointer.html).* @@ -38,21 +38,68 @@ pub use intrinsics::write_bytes; /// Executes the destructor (if any) of the pointed-to value. /// -/// This has two use cases: +/// This is semantically equivalent to calling [`ptr::read`] and discarding +/// the result, but has the following advantages: /// /// * It is *required* to use `drop_in_place` to drop unsized types like /// trait objects, because they can't be read out onto the stack and /// dropped normally. /// -/// * It is friendlier to the optimizer to do this over `ptr::read` when +/// * It is friendlier to the optimizer to do this over [`ptr::read`] when /// dropping manually allocated memory (e.g. when writing Box/Rc/Vec), /// as the compiler doesn't need to prove that it's sound to elide the /// copy. /// +/// [`ptr::read`]: ./fn.read.html +/// /// # Safety /// -/// This has all the same safety problems as `ptr::read` with respect to -/// invalid pointers, types, and double drops. +/// `drop_in_place` is unsafe because it dereferences a raw pointer. The caller +/// must ensure that the pointer points to a valid value of type `T`. +/// +/// # [Undefined Behavior] +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `to_drop` must point to valid memory. +/// +/// * `to_drop` must be properly aligned. +/// +/// Additionally, if `T` is not [`Copy`], using the pointed-to value after +/// calling `drop_in_place` can cause undefined behavior. Note that `*to_drop = +/// foo` counts as a use because it will cause the the value to be dropped +/// again. [`write`] can be used to overwrite data without causing it to be +/// dropped. +/// +/// [`Copy`]: ../marker/trait.Copy.html +/// [`write`]: ./fn.write.html +/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html +/// +/// # Examples +/// +/// Manually remove the last item from a vector: +/// +/// ``` +/// use std::ptr; +/// use std::rc::Rc; +/// +/// let last = Rc::new(1); +/// let weak = Rc::downgrade(&last); +/// +/// let mut v = vec![Rc::new(0), last]; +/// +/// unsafe { +/// // Without a call `drop_in_place`, the last item would never be dropped, +/// // and the memory it manages would be leaked. +/// ptr::drop_in_place(&mut v[1]); +/// v.set_len(1); +/// } +/// +/// assert_eq!(v, &[0.into()]); +/// +/// // Ensure that the last item was dropped. +/// assert!(weak.upgrade().is_none()); +/// ``` #[stable(feature = "drop_in_place", since = "1.8.0")] #[lang = "drop_in_place"] #[allow(unconditional_recursion)] @@ -93,17 +140,32 @@ pub const fn null_mut() -> *mut T { 0 as *mut T } /// Swaps the values at two mutable locations of the same type, without /// deinitializing either. /// -/// The values pointed at by `x` and `y` may overlap, unlike `mem::swap` which -/// is otherwise equivalent. If the values do overlap, then the overlapping -/// region of memory from `x` will be used. This is demonstrated in the -/// examples section below. +/// But for the following two exceptions, this function is semantically +/// equivalent to [`mem::swap`]: +/// +/// * It operates on raw pointers instead of references. When references are +/// available, [`mem::swap`] should be preferred. +/// +/// * The two pointed-to values may overlap. If the values do overlap, then the +/// overlapping region of memory from `x` will be used. This is demonstrated +/// in the examples below. +/// +/// [`mem::swap`]: ../mem/fn.swap.html /// /// # Safety /// -/// This function copies the memory through the raw pointers passed to it -/// as arguments. +/// `swap` is unsafe because it dereferences a raw pointer. The caller must +/// ensure that both pointers point to valid values of type `T`. +/// +/// # [Undefined Behavior] +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `x` and `y` must point to valid, initialized memory. /// -/// Ensure that these pointers are valid before calling `swap`. +/// * `x` and `y` must be properly aligned. +/// +/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// @@ -241,13 +303,46 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { } } -/// Replaces the value at `dest` with `src`, returning the old -/// value, without dropping either. +/// Replaces the value at `dest` with `src`, returning the old value, without +/// dropping either. +/// +/// This function is semantically equivalent to [`mem::replace`] except that it +/// operates on raw pointers instead of references. When references are +/// available, [`mem::replace`] should be preferred. /// /// # Safety /// -/// This is only unsafe because it accepts a raw pointer. -/// Otherwise, this operation is identical to `mem::replace`. +/// `replace` is unsafe because it dereferences a raw pointer. The caller +/// must ensure that the pointer points to a valid value of type `T`. +/// +/// [`mem::replace`]: ../mem/fn.replace.html +/// +/// # [Undefined Behavior] +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `dest` must point to valid, initialized memory. +/// +/// * `dest` must be properly aligned. +/// +/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html +/// +/// # Examples +/// +/// ``` +/// use std::ptr; +/// +/// let mut rust = vec!['b', 'u', 's', 't']; +/// +/// // `mem::replace` would have the same effect without requiring the unsafe +/// // block. +/// let b = unsafe { +/// ptr::replace(&mut a[0], 'r') +/// }; +/// +/// assert_eq!(b, 'b'); +/// assert_eq!(rust, &['r', 'u', 's', 't']); +/// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn replace(dest: *mut T, mut src: T) -> T { @@ -260,14 +355,29 @@ pub unsafe fn replace(dest: *mut T, mut src: T) -> T { /// /// # Safety /// -/// Beyond accepting a raw pointer, this is unsafe because it semantically -/// moves the value out of `src` without preventing further usage of `src`. -/// If `T` is not `Copy`, then care must be taken to ensure that the value at -/// `src` is not used before the data is overwritten again (e.g. with `write`, -/// `write_bytes`, or `copy`). Note that `*src = foo` counts as a use -/// because it will attempt to drop the value previously at `*src`. +/// `read` is unsafe because it dereferences a raw pointer. The caller +/// must ensure that the pointer points to a valid value of type `T`. +/// +/// # [Undefined Behavior] /// -/// The pointer must be aligned; use `read_unaligned` if that is not the case. +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `src` must point to valid, initialized memory. +/// +/// * `src` must be properly aligned. Use [`read_unaligned`] if this is not the +/// case. +/// +/// Additionally, if `T` is not [`Copy`], only the returned value *or* the +/// pointed-to value can be used or dropped after calling `read`. `read` creates +/// a bitwise copy of `T`, regardless of whether `T: Copy`, which can result +/// in undefined behavior if both copies are used. Note that `*src = foo` counts +/// as a use because it will attempt to drop the value previously at `*src`. +/// [`write`] can be used to overwrite data without causing it to be dropped. +/// +/// [`Copy`]: ../marker/trait.Copy.html +/// [`read_unaligned`]: ./fn.read_unaligned.html +/// [`write`]: ./fn.write.html +/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// @@ -281,6 +391,44 @@ pub unsafe fn replace(dest: *mut T, mut src: T) -> T { /// assert_eq!(std::ptr::read(y), 12); /// } /// ``` +/// +/// Manually implement [`mem::swap`]: +/// +/// ``` +/// use std::ptr; +/// +/// fn swap(a: &mut T, b: &mut T) { +/// unsafe { +/// // Create a bitwise copy of the value at `a` in `tmp`. +/// let tmp = ptr::read(a); +/// +/// // Exiting at this point (either by explicitly returning or by +/// // calling a function which panics) would cause the value in `tmp` to +/// // be dropped while the same value is still referenced by `a`. This +/// // could trigger undefined behavior if `T` is not `Copy`. +/// +/// // Create a bitwise copy of the value at `b` in `a`. +/// // This is safe because mutable references cannot alias. +/// ptr::copy_nonoverlapping(b, a, 1); +/// +/// // As above, exiting here could trigger undefined behavior because +/// // the same value is referenced by `a` and `b`. +/// +/// // Move `tmp` into `b`. +/// ptr::write(b, tmp); +/// } +/// } +/// +/// let mut foo = "foo".to_owned(); +/// let mut bar = "bar".to_owned(); +/// +/// swap(&mut foo, &mut bar); +/// +/// assert_eq!(foo, "bar"); +/// assert_eq!(bar, "foo"); +/// ``` +/// +/// [`mem::swap`]: ../mem/fn.swap.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn read(src: *const T) -> T { @@ -292,28 +440,66 @@ pub unsafe fn read(src: *const T) -> T { /// Reads the value from `src` without moving it. This leaves the /// memory in `src` unchanged. /// -/// Unlike `read`, the pointer may be unaligned. +/// Unlike [`read`], `read_unaligned` works with unaligned pointers. /// -/// # Safety +/// [`read`]: ./fn.read.html +/// +/// `read_unaligned` is unsafe because it dereferences a raw pointer. The caller +/// must ensure that the pointer points to a valid value of type `T`. +/// +/// # [Undefined Behavior] +/// +/// Behavior is undefined if any of the following conditions are violated: /// -/// Beyond accepting a raw pointer, this is unsafe because it semantically -/// moves the value out of `src` without preventing further usage of `src`. -/// If `T` is not `Copy`, then care must be taken to ensure that the value at -/// `src` is not used before the data is overwritten again (e.g. with `write`, -/// `write_bytes`, or `copy`). Note that `*src = foo` counts as a use -/// because it will attempt to drop the value previously at `*src`. +/// * `src` must point to valid, initialized memory. +/// +/// Additionally, if `T` is not [`Copy`], only the returned value *or* the +/// pointed-to value can be used or dropped after calling `read_unaligned`. +/// `read_unaligned` creates a bitwise copy of `T`, regardless of whether `T: +/// Copy`, and this can result in undefined behavior if both copies are used. +/// Note that `*src = foo` counts as a use because it will attempt to drop the +/// value previously at `*src`. [`write_unaligned`] can be used to overwrite +/// data without causing it to be dropped. +/// +/// [`Copy`]: ../marker/trait.Copy.html +/// [`write_unaligned`]: ./fn.write_unaligned.html +/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// -/// Basic usage: +/// Access members of a packed struct by reference: /// /// ``` -/// let x = 12; -/// let y = &x as *const i32; +/// use std::ptr; /// -/// unsafe { -/// assert_eq!(std::ptr::read_unaligned(y), 12); +/// #[repr(packed, C)] +/// #[derive(Default)] +/// struct Packed { +/// _padding: u8, +/// unaligned: u32, /// } +/// +/// let x = Packed { +/// _padding: 0x00, +/// unaligned: 0x01020304, +/// }; +/// +/// let v = unsafe { +/// // Take a reference to a 32-bit integer which is not aligned. +/// let unaligned = &x.unaligned; +/// +/// // Dereferencing normally will emit an unaligned load instruction, +/// // causing undefined behavior. +/// // let v = *unaligned; // ERROR +/// +/// // Instead, use `read_unaligned` to read improperly aligned values. +/// let v = ptr::read_unaligned(unaligned); +/// +/// v +/// }; +/// +/// // Accessing unaligned values directly is safe. +/// assert!(x.unaligned == v); /// ``` #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] @@ -328,11 +514,7 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// Overwrites a memory location with the given value without reading or /// dropping the old value. /// -/// # Safety -/// -/// This operation is marked unsafe because it accepts a raw pointer. -/// -/// It does not drop the contents of `dst`. This is safe, but it could leak +/// `write` does not drop the contents of `dst`. This is safe, but it could leak /// allocations or resources, so care must be taken not to overwrite an object /// that should be dropped. /// @@ -340,9 +522,26 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// location pointed to by `dst`. /// /// This is appropriate for initializing uninitialized memory, or overwriting -/// memory that has previously been `read` from. +/// memory that has previously been [`read`] from. +/// +/// [`read`]: ./fn.read.html +/// +/// # Safety +/// +/// `write` is unsafe because it dereferences a raw pointer. +/// +/// # [Undefined Behavior] +/// +/// `write` can trigger undefined behavior if any of the following conditions +/// are violated: /// -/// The pointer must be aligned; use `write_unaligned` if that is not the case. +/// * `dst` must point to valid memory. +/// +/// * `dst` must be properly aligned. Use [`write_unaligned`] if this is not the +/// case. +/// +/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html +/// [`write_unaligned`]: ./fn.write_unaligned.html /// /// # Examples /// @@ -358,6 +557,30 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// assert_eq!(std::ptr::read(y), 12); /// } /// ``` +/// +/// Manually implement [`mem::swap`]: +/// +/// ``` +/// use std::ptr; +/// +/// fn swap(a: &mut T, b: &mut T) { +/// unsafe { +/// let tmp = ptr::read(a); +/// ptr::copy_nonoverlapping(b, a, 1); +/// ptr::write(b, tmp); +/// } +/// } +/// +/// let mut foo = "foo".to_owned(); +/// let mut bar = "bar".to_owned(); +/// +/// swap(&mut foo, &mut bar); +/// +/// assert_eq!(foo, "bar"); +/// assert_eq!(bar, "foo"); +/// ``` +/// +/// [`mem::swap`]: ../mem/fn.swap.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn write(dst: *mut T, src: T) { @@ -367,36 +590,65 @@ pub unsafe fn write(dst: *mut T, src: T) { /// Overwrites a memory location with the given value without reading or /// dropping the old value. /// -/// Unlike `write`, the pointer may be unaligned. +/// Unlike [`write`], the pointer may be unaligned. /// -/// # Safety -/// -/// This operation is marked unsafe because it accepts a raw pointer. -/// -/// It does not drop the contents of `dst`. This is safe, but it could leak -/// allocations or resources, so care must be taken not to overwrite an object -/// that should be dropped. +/// `write_unaligned` does not drop the contents of `dst`. This is safe, but it +/// could leak allocations or resources, so care must be taken not to overwrite +/// an object that should be dropped. /// /// Additionally, it does not drop `src`. Semantically, `src` is moved into the /// location pointed to by `dst`. /// /// This is appropriate for initializing uninitialized memory, or overwriting -/// memory that has previously been `read` from. +/// memory that has previously been [`read`] from. +/// +/// [`write`]: ./fn.write.html +/// [`read_unaligned`]: ./fn.read_unaligned.html +/// +/// # Safety +/// +/// `write_unaligned` is unsafe because it dereferences a raw pointer. +/// +/// # [Undefined Behavior] +/// +/// `write_unaligned` can trigger undefined behavior if any of the following +/// conditions are violated: +/// +/// * `dst` must point to valid memory. +/// +/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// -/// Basic usage: +/// Access fields in a packed struct: /// /// ``` -/// let mut x = 0; -/// let y = &mut x as *mut i32; -/// let z = 12; +/// use std::{mem, ptr}; +/// +/// #[repr(packed, C)] +/// #[derive(Default)] +/// struct Packed { +/// _padding: u8, +/// unaligned: u32, +/// } +/// +/// let v = 0x01020304; +/// let mut x: Packed = unsafe { mem::zeroed() }; /// /// unsafe { -/// std::ptr::write_unaligned(y, z); -/// assert_eq!(std::ptr::read_unaligned(y), 12); +/// // Take a reference to a 32-bit integer which is not aligned. +/// let unaligned = &mut x.unaligned; +/// +/// // Dereferencing normally will emit an unaligned store instruction, +/// // causing undefined behavior. +/// // *unaligned = v; // ERROR +/// +/// // Instead, use `write_unaligned` to write improperly aligned values. +/// ptr::write_unaligned(unaligned, v); /// } -/// ``` +/// +/// // Accessing unaligned values directly is safe. +/// assert!(x.unaligned == v); #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] pub unsafe fn write_unaligned(dst: *mut T, src: T) { @@ -429,12 +681,28 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// /// # Safety /// -/// Beyond accepting a raw pointer, this is unsafe because it semantically -/// moves the value out of `src` without preventing further usage of `src`. -/// If `T` is not `Copy`, then care must be taken to ensure that the value at -/// `src` is not used before the data is overwritten again (e.g. with `write`, -/// `write_bytes`, or `copy`). Note that `*src = foo` counts as a use -/// because it will attempt to drop the value previously at `*src`. +/// `read_volatile` is unsafe because it dereferences a raw pointer. The caller +/// must ensure that the pointer points to a valid value of type `T`. +/// +/// # [Undefined Behavior] +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `src` must point to valid, initialized memory. +/// +/// * `src` must be properly aligned. +/// +/// Additionally, if `T` is not [`Copy`], only the returned value *or* the +/// pointed-to value can be used or dropped after calling `read_volatile`. +/// `read_volatile` creates a bitwise copy of `T`, regardless of whether `T: +/// Copy`, which can result in undefined behavior if both copies are used. +/// Note that `*src = foo` counts as a use because it will attempt to drop the +/// value previously at `*src`. [`write_volatile`] can be used to overwrite +/// data without causing it to be dropped. +/// +/// [`Copy`]: ../marker/trait.Copy.html +/// [`write_volatile`]: ./fn.write_volatile.html +/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// @@ -461,6 +729,13 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// to not be elided or reordered by the compiler across other volatile /// operations. /// +/// `write_volatile` does not drop the contents of `dst`. This is safe, but it +/// could leak allocations or resources, so care must be taken not to overwrite +/// an object that should be dropped. +/// +/// Additionally, it does not drop `src`. Semantically, `src` is moved into the +/// location pointed to by `dst`. +/// /// # Notes /// /// Rust does not currently have a rigorously and formally defined memory model, @@ -477,14 +752,18 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// /// # Safety /// -/// This operation is marked unsafe because it accepts a raw pointer. +/// `write_volatile` is unsafe because it dereferences a raw pointer. /// -/// It does not drop the contents of `dst`. This is safe, but it could leak -/// allocations or resources, so care must be taken not to overwrite an object -/// that should be dropped. +/// # [Undefined Behavior] /// -/// This is appropriate for initializing uninitialized memory, or overwriting -/// memory that has previously been `read` from. +/// `write_volatile` can trigger undefined behavior if any of the following +/// conditions are violated: +/// +/// * `dst` must point to valid memory. +/// +/// * `dst` must be properly aligned. +/// +/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// From ee259e4dd340f9532511b7249e4eb961f111b63f Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sat, 7 Apr 2018 15:51:25 -0700 Subject: [PATCH 2/9] Change `write_bytes` test causing UB to `no_run` This also fixes improper text wrapping. --- src/libcore/intrinsics.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index d6bd2b868554c..8e3180cd2a6f9 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -992,11 +992,11 @@ extern "rust-intrinsic" { /// /// * The two regions of memory must *not* overlap. /// - /// Additionally, if `T` is not [`Copy`](../marker/trait.Copy), only the region at `src` *or* the - /// region at `dst` can be used or dropped after calling - /// `copy_nonoverlapping`. `copy_nonoverlapping` creates bitwise copies of - /// `T`, regardless of whether `T: Copy`, which can result in undefined - /// behavior if both copies are used. + /// Additionally, if `T` is not [`Copy`](../marker/trait.Copy), only the + /// region at `src` *or* the region at `dst` can be used or dropped after + /// calling `copy_nonoverlapping`. `copy_nonoverlapping` creates bitwise + /// copies of `T`, regardless of whether `T: Copy`, which can result in + /// undefined behavior if both copies are used. /// /// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// @@ -1149,7 +1149,7 @@ extern "rust-intrinsic" { /// /// Creating an invalid value: /// - /// ```ignore + /// ```no_run /// use std::{mem, ptr}; /// /// let mut v = Box::new(0i32); @@ -1161,6 +1161,7 @@ extern "rust-intrinsic" { /// } /// /// // At this point, using or dropping `v` results in undefined behavior. + /// // v = Box::new(0i32); // ERROR /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn write_bytes(dst: *mut T, val: u8, count: usize); From b564c4a0ee96acb0a68b8421b6cecac47e2a2e8b Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sat, 7 Apr 2018 17:20:20 -0700 Subject: [PATCH 3/9] Fix example for `ptr::replace` --- src/libcore/ptr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 98d5030477b51..9069feab06c84 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -337,7 +337,7 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { /// // `mem::replace` would have the same effect without requiring the unsafe /// // block. /// let b = unsafe { -/// ptr::replace(&mut a[0], 'r') +/// ptr::replace(&mut rust[0], 'r') /// }; /// /// assert_eq!(b, 'b'); From 6eceb94d09636d272f8448d0eb26e072b891cb45 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sat, 7 Apr 2018 17:22:27 -0700 Subject: [PATCH 4/9] Don't link "Undefined Behavior" heading The rendered version does not make clear that this is a link to another page, and it breaks the anchor link. --- src/libcore/intrinsics.rs | 9 +++------ src/libcore/ptr.rs | 31 +++++++++---------------------- 2 files changed, 12 insertions(+), 28 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 8e3180cd2a6f9..daa43337fd79c 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -975,7 +975,7 @@ extern "rust-intrinsic" { /// The caller must ensure that `src` points to a valid sequence of type /// `T`. /// - /// # [Undefined Behavior] + /// # Undefined Behavior /// /// Behavior is undefined if any of the following conditions are violated: /// @@ -998,8 +998,6 @@ extern "rust-intrinsic" { /// copies of `T`, regardless of whether `T: Copy`, which can result in /// undefined behavior if both copies are used. /// - /// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html - /// /// # Examples /// /// Manually implement [`Vec::append`]: @@ -1065,7 +1063,7 @@ extern "rust-intrinsic" { /// `copy` is unsafe because it dereferences a raw pointer. The caller must /// ensure that `src` points to a valid sequence of type `T`. /// - /// # [Undefined Behavior] + /// # Undefined Behavior /// /// Behavior is undefined if any of the following conditions are violated: /// @@ -1086,7 +1084,6 @@ extern "rust-intrinsic" { /// can result in undefined behavior if both copies are used. /// /// [`Copy`]: ../marker/trait.Copy.html - /// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// @@ -1118,7 +1115,7 @@ extern "rust-intrinsic" { /// `write_bytes` is unsafe because it dereferences a raw pointer. The /// caller must ensure that the poiinter points to a valid value of type `T`. /// - /// # [Undefined Behavior] + /// # Undefined Behavior /// /// Behavior is undefined if any of the following conditions are violated: /// diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 9069feab06c84..4cb9c655441d9 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -57,7 +57,7 @@ pub use intrinsics::write_bytes; /// `drop_in_place` is unsafe because it dereferences a raw pointer. The caller /// must ensure that the pointer points to a valid value of type `T`. /// -/// # [Undefined Behavior] +/// # Undefined Behavior /// /// Behavior is undefined if any of the following conditions are violated: /// @@ -73,7 +73,6 @@ pub use intrinsics::write_bytes; /// /// [`Copy`]: ../marker/trait.Copy.html /// [`write`]: ./fn.write.html -/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// @@ -157,7 +156,7 @@ pub const fn null_mut() -> *mut T { 0 as *mut T } /// `swap` is unsafe because it dereferences a raw pointer. The caller must /// ensure that both pointers point to valid values of type `T`. /// -/// # [Undefined Behavior] +/// # Undefined Behavior /// /// Behavior is undefined if any of the following conditions are violated: /// @@ -165,8 +164,6 @@ pub const fn null_mut() -> *mut T { 0 as *mut T } /// /// * `x` and `y` must be properly aligned. /// -/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html -/// /// # Examples /// /// Swapping two non-overlapping regions: @@ -317,7 +314,7 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { /// /// [`mem::replace`]: ../mem/fn.replace.html /// -/// # [Undefined Behavior] +/// # Undefined Behavior /// /// Behavior is undefined if any of the following conditions are violated: /// @@ -325,8 +322,6 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { /// /// * `dest` must be properly aligned. /// -/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html -/// /// # Examples /// /// ``` @@ -358,7 +353,7 @@ pub unsafe fn replace(dest: *mut T, mut src: T) -> T { /// `read` is unsafe because it dereferences a raw pointer. The caller /// must ensure that the pointer points to a valid value of type `T`. /// -/// # [Undefined Behavior] +/// # Undefined Behavior /// /// Behavior is undefined if any of the following conditions are violated: /// @@ -377,7 +372,6 @@ pub unsafe fn replace(dest: *mut T, mut src: T) -> T { /// [`Copy`]: ../marker/trait.Copy.html /// [`read_unaligned`]: ./fn.read_unaligned.html /// [`write`]: ./fn.write.html -/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// @@ -447,7 +441,7 @@ pub unsafe fn read(src: *const T) -> T { /// `read_unaligned` is unsafe because it dereferences a raw pointer. The caller /// must ensure that the pointer points to a valid value of type `T`. /// -/// # [Undefined Behavior] +/// # Undefined Behavior /// /// Behavior is undefined if any of the following conditions are violated: /// @@ -463,7 +457,6 @@ pub unsafe fn read(src: *const T) -> T { /// /// [`Copy`]: ../marker/trait.Copy.html /// [`write_unaligned`]: ./fn.write_unaligned.html -/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// @@ -530,7 +523,7 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// /// `write` is unsafe because it dereferences a raw pointer. /// -/// # [Undefined Behavior] +/// # Undefined Behavior /// /// `write` can trigger undefined behavior if any of the following conditions /// are violated: @@ -540,7 +533,6 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// * `dst` must be properly aligned. Use [`write_unaligned`] if this is not the /// case. /// -/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// [`write_unaligned`]: ./fn.write_unaligned.html /// /// # Examples @@ -609,15 +601,13 @@ pub unsafe fn write(dst: *mut T, src: T) { /// /// `write_unaligned` is unsafe because it dereferences a raw pointer. /// -/// # [Undefined Behavior] +/// # Undefined Behavior /// /// `write_unaligned` can trigger undefined behavior if any of the following /// conditions are violated: /// /// * `dst` must point to valid memory. /// -/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html -/// /// # Examples /// /// Access fields in a packed struct: @@ -684,7 +674,7 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// `read_volatile` is unsafe because it dereferences a raw pointer. The caller /// must ensure that the pointer points to a valid value of type `T`. /// -/// # [Undefined Behavior] +/// # Undefined Behavior /// /// Behavior is undefined if any of the following conditions are violated: /// @@ -702,7 +692,6 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// /// [`Copy`]: ../marker/trait.Copy.html /// [`write_volatile`]: ./fn.write_volatile.html -/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// @@ -754,7 +743,7 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// /// `write_volatile` is unsafe because it dereferences a raw pointer. /// -/// # [Undefined Behavior] +/// # Undefined Behavior /// /// `write_volatile` can trigger undefined behavior if any of the following /// conditions are violated: @@ -763,8 +752,6 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// /// * `dst` must be properly aligned. /// -/// [Undefined Behavior]: ../../reference/behavior-considered-undefined.html -/// /// # Examples /// /// Basic usage: From 422b6164e505bc240948dc6e420a82c89ead0711 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sat, 7 Apr 2018 17:28:10 -0700 Subject: [PATCH 5/9] Fix broken link in `write_unaligned` docs --- src/libcore/ptr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 4cb9c655441d9..c679a1a2456b1 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -592,7 +592,7 @@ pub unsafe fn write(dst: *mut T, src: T) { /// location pointed to by `dst`. /// /// This is appropriate for initializing uninitialized memory, or overwriting -/// memory that has previously been [`read`] from. +/// memory that has previously been read with [`read_unaligned`]. /// /// [`write`]: ./fn.write.html /// [`read_unaligned`]: ./fn.read_unaligned.html From d7ce9a213c11f825b8b47f7d9fd970cfb97033bd Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sat, 7 Apr 2018 20:45:16 -0700 Subject: [PATCH 6/9] Fix broken relative links --- src/libcore/intrinsics.rs | 12 ++++++------ src/libcore/ptr.rs | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index daa43337fd79c..8c510842c2a91 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -992,11 +992,11 @@ extern "rust-intrinsic" { /// /// * The two regions of memory must *not* overlap. /// - /// Additionally, if `T` is not [`Copy`](../marker/trait.Copy), only the - /// region at `src` *or* the region at `dst` can be used or dropped after - /// calling `copy_nonoverlapping`. `copy_nonoverlapping` creates bitwise - /// copies of `T`, regardless of whether `T: Copy`, which can result in - /// undefined behavior if both copies are used. + /// Additionally, if `T` is not [`Copy`](../marker/trait.Copy.html), only + /// the region at `src` *or* the region at `dst` can be used or dropped + /// after calling `copy_nonoverlapping`. `copy_nonoverlapping` creates + /// bitwise copies of `T`, regardless of whether `T: Copy`, which can result + /// in undefined behavior if both copies are used. /// /// # Examples /// @@ -1043,7 +1043,7 @@ extern "rust-intrinsic" { /// assert!(b.is_empty()); /// ``` /// - /// [`Vec::append()`]: ../vec/struct.Vec.html#method.append + /// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append #[stable(feature = "rust1", since = "1.0.0")] pub fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index c679a1a2456b1..962fb0f31a407 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -50,7 +50,7 @@ pub use intrinsics::write_bytes; /// as the compiler doesn't need to prove that it's sound to elide the /// copy. /// -/// [`ptr::read`]: ./fn.read.html +/// [`ptr::read`]: ../ptr/fn.read.html /// /// # Safety /// @@ -72,7 +72,7 @@ pub use intrinsics::write_bytes; /// dropped. /// /// [`Copy`]: ../marker/trait.Copy.html -/// [`write`]: ./fn.write.html +/// [`write`]: ../ptr/fn.write.html /// /// # Examples /// From d7209d5babae4e1e428771287eaca6165e43972c Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 9 Apr 2018 14:23:08 -0700 Subject: [PATCH 7/9] Fix various nits from PR review - Remove redundant "unsafe" from module description. - Add a missing `Safety` heading to `read_unaligned`. - Remove weasel words in `Undefined Behavior` description for `write{,_unaligned,_bytes}`. --- src/libcore/ptr.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 962fb0f31a407..3d15e4b165893 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -10,7 +10,7 @@ // FIXME: talk about offset, copy_memory, copy_nonoverlapping_memory -//! Manually manage memory through raw, unsafe pointers. +//! Manually manage memory through raw pointers. //! //! *[See also the pointer primitive types](../../std/primitive.pointer.html).* @@ -438,6 +438,8 @@ pub unsafe fn read(src: *const T) -> T { /// /// [`read`]: ./fn.read.html /// +/// # Safety +/// /// `read_unaligned` is unsafe because it dereferences a raw pointer. The caller /// must ensure that the pointer points to a valid value of type `T`. /// @@ -525,8 +527,7 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// /// # Undefined Behavior /// -/// `write` can trigger undefined behavior if any of the following conditions -/// are violated: +/// Behavior is undefined if any of the following conditions are violated: /// /// * `dst` must point to valid memory. /// @@ -603,8 +604,7 @@ pub unsafe fn write(dst: *mut T, src: T) { /// /// # Undefined Behavior /// -/// `write_unaligned` can trigger undefined behavior if any of the following -/// conditions are violated: +/// Behavior is undefined if any of the following conditions are violated: /// /// * `dst` must point to valid memory. /// @@ -745,8 +745,7 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// /// # Undefined Behavior /// -/// `write_volatile` can trigger undefined behavior if any of the following -/// conditions are violated: +/// Behavior is undefined if any of the following conditions are violated: /// /// * `dst` must point to valid memory. /// From e350ba48ed80c000fd2d2b5ac37e53a9efe1f587 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 9 May 2018 14:14:43 -0700 Subject: [PATCH 8/9] Use the "Safety" heading instead of "Undefined Behavior" --- src/libcore/intrinsics.rs | 30 +++++++------------------- src/libcore/ptr.rs | 44 +-------------------------------------- 2 files changed, 9 insertions(+), 65 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 8c510842c2a91..df3f6c430311a 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -971,12 +971,6 @@ extern "rust-intrinsic" { /// /// # Safety /// - /// `copy_nonoverlapping` is unsafe because it dereferences a raw pointer. - /// The caller must ensure that `src` points to a valid sequence of type - /// `T`. - /// - /// # Undefined Behavior - /// /// Behavior is undefined if any of the following conditions are violated: /// /// * The region of memory which begins at `src` and has a length of @@ -986,17 +980,19 @@ extern "rust-intrinsic" { /// `count * size_of::()` bytes must be valid (but may or may not be /// initialized). /// + /// * The two regions of memory must *not* overlap. + /// /// * `src` must be properly aligned. /// /// * `dst` must be properly aligned. /// - /// * The two regions of memory must *not* overlap. + /// Additionally, if `T` is not [`Copy`], only the region at `src` *or* the + /// region at `dst` can be used or dropped after calling + /// `copy_nonoverlapping`. `copy_nonoverlapping` creates bitwise copies of + /// `T`, regardless of whether `T: Copy`, which can result in undefined + /// behavior if both copies are used. /// - /// Additionally, if `T` is not [`Copy`](../marker/trait.Copy.html), only - /// the region at `src` *or* the region at `dst` can be used or dropped - /// after calling `copy_nonoverlapping`. `copy_nonoverlapping` creates - /// bitwise copies of `T`, regardless of whether `T: Copy`, which can result - /// in undefined behavior if both copies are used. + /// [`Copy`]: ../marker/trait.Copy.html /// /// # Examples /// @@ -1060,11 +1056,6 @@ extern "rust-intrinsic" { /// /// # Safety /// - /// `copy` is unsafe because it dereferences a raw pointer. The caller must - /// ensure that `src` points to a valid sequence of type `T`. - /// - /// # Undefined Behavior - /// /// Behavior is undefined if any of the following conditions are violated: /// /// * The region of memory which begins at `src` and has a length of @@ -1112,11 +1103,6 @@ extern "rust-intrinsic" { /// /// # Safety /// - /// `write_bytes` is unsafe because it dereferences a raw pointer. The - /// caller must ensure that the poiinter points to a valid value of type `T`. - /// - /// # Undefined Behavior - /// /// Behavior is undefined if any of the following conditions are violated: /// /// * The region of memory which begins at `dst` and has a length of diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 3d15e4b165893..50627ee464d39 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -54,11 +54,6 @@ pub use intrinsics::write_bytes; /// /// # Safety /// -/// `drop_in_place` is unsafe because it dereferences a raw pointer. The caller -/// must ensure that the pointer points to a valid value of type `T`. -/// -/// # Undefined Behavior -/// /// Behavior is undefined if any of the following conditions are violated: /// /// * `to_drop` must point to valid memory. @@ -153,11 +148,6 @@ pub const fn null_mut() -> *mut T { 0 as *mut T } /// /// # Safety /// -/// `swap` is unsafe because it dereferences a raw pointer. The caller must -/// ensure that both pointers point to valid values of type `T`. -/// -/// # Undefined Behavior -/// /// Behavior is undefined if any of the following conditions are violated: /// /// * `x` and `y` must point to valid, initialized memory. @@ -307,14 +297,9 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { /// operates on raw pointers instead of references. When references are /// available, [`mem::replace`] should be preferred. /// -/// # Safety -/// -/// `replace` is unsafe because it dereferences a raw pointer. The caller -/// must ensure that the pointer points to a valid value of type `T`. -/// /// [`mem::replace`]: ../mem/fn.replace.html /// -/// # Undefined Behavior +/// # Safety /// /// Behavior is undefined if any of the following conditions are violated: /// @@ -350,11 +335,6 @@ pub unsafe fn replace(dest: *mut T, mut src: T) -> T { /// /// # Safety /// -/// `read` is unsafe because it dereferences a raw pointer. The caller -/// must ensure that the pointer points to a valid value of type `T`. -/// -/// # Undefined Behavior -/// /// Behavior is undefined if any of the following conditions are violated: /// /// * `src` must point to valid, initialized memory. @@ -440,11 +420,6 @@ pub unsafe fn read(src: *const T) -> T { /// /// # Safety /// -/// `read_unaligned` is unsafe because it dereferences a raw pointer. The caller -/// must ensure that the pointer points to a valid value of type `T`. -/// -/// # Undefined Behavior -/// /// Behavior is undefined if any of the following conditions are violated: /// /// * `src` must point to valid, initialized memory. @@ -523,10 +498,6 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// /// # Safety /// -/// `write` is unsafe because it dereferences a raw pointer. -/// -/// # Undefined Behavior -/// /// Behavior is undefined if any of the following conditions are violated: /// /// * `dst` must point to valid memory. @@ -600,10 +571,6 @@ pub unsafe fn write(dst: *mut T, src: T) { /// /// # Safety /// -/// `write_unaligned` is unsafe because it dereferences a raw pointer. -/// -/// # Undefined Behavior -/// /// Behavior is undefined if any of the following conditions are violated: /// /// * `dst` must point to valid memory. @@ -671,11 +638,6 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// /// # Safety /// -/// `read_volatile` is unsafe because it dereferences a raw pointer. The caller -/// must ensure that the pointer points to a valid value of type `T`. -/// -/// # Undefined Behavior -/// /// Behavior is undefined if any of the following conditions are violated: /// /// * `src` must point to valid, initialized memory. @@ -741,10 +703,6 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// /// # Safety /// -/// `write_volatile` is unsafe because it dereferences a raw pointer. -/// -/// # Undefined Behavior -/// /// Behavior is undefined if any of the following conditions are violated: /// /// * `dst` must point to valid memory. From 827251e92bef9bd613cf44e2dc074fa1dc71ea0f Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 9 May 2018 15:52:16 -0700 Subject: [PATCH 9/9] Shorten ownership safety discussion in `read_volatile` Non-`Copy` types should not be in volatile memory. --- src/libcore/ptr.rs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 50627ee464d39..f3cf206876651 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -622,6 +622,11 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// to not be elided or reordered by the compiler across other volatile /// operations. /// +/// Memory read with `read_volatile` should almost always be written to using +/// [`write_volatile`]. +/// +/// [`write_volatile`]: ./fn.write_volatile.html +/// /// # Notes /// /// Rust does not currently have a rigorously and formally defined memory model, @@ -644,16 +649,13 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// /// * `src` must be properly aligned. /// -/// Additionally, if `T` is not [`Copy`], only the returned value *or* the -/// pointed-to value can be used or dropped after calling `read_volatile`. -/// `read_volatile` creates a bitwise copy of `T`, regardless of whether `T: -/// Copy`, which can result in undefined behavior if both copies are used. -/// Note that `*src = foo` counts as a use because it will attempt to drop the -/// value previously at `*src`. [`write_volatile`] can be used to overwrite -/// data without causing it to be dropped. +/// Like [`read`], `read_volatile` creates a bitwise copy of the pointed-to +/// object, regardless of whether `T` is [`Copy`]. Using both values can cause +/// undefined behavior. However, storing non-[`Copy`] data in I/O memory is +/// almost certainly incorrect. /// /// [`Copy`]: ../marker/trait.Copy.html -/// [`write_volatile`]: ./fn.write_volatile.html +/// [`read`]: ./fn.read.html /// /// # Examples /// @@ -680,6 +682,9 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// to not be elided or reordered by the compiler across other volatile /// operations. /// +/// Memory written with `write_volatile` should almost always be read from using +/// [`read_volatile`]. +/// /// `write_volatile` does not drop the contents of `dst`. This is safe, but it /// could leak allocations or resources, so care must be taken not to overwrite /// an object that should be dropped. @@ -687,6 +692,8 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// Additionally, it does not drop `src`. Semantically, `src` is moved into the /// location pointed to by `dst`. /// +/// [`read_volatile`]: ./fn.read_volatile.html +/// /// # Notes /// /// Rust does not currently have a rigorously and formally defined memory model,