]> git.lizzy.rs Git - rust.git/commitdiff
Rewrite docs for `std::ptr`
authorDylan MacKenzie <ecstaticmorse@gmail.com>
Fri, 6 Apr 2018 07:34:45 +0000 (00:34 -0700)
committerDylan MacKenzie <ecstaticmorse@gmail.com>
Sat, 7 Apr 2018 22:11:41 +0000 (15:11 -0700)
- 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
src/libcore/ptr.rs

index 83274682250b0911f2e41b61c43894dbe4bed4fd..d6bd2b868554c03bddd99218bd522b07484eb130 100644 (file)
     /// value is not necessarily valid to be used to actually access memory.
     pub fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
 
-    /// Copies `count * size_of<T>` bytes from `src` to `dst`. The source
-    /// and destination may *not* overlap.
+    /// Copies `count * size_of::<T>()` 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::<T>()` bytes must be *both* valid and initialized.
+    ///
+    /// * The region of memory which begins at `dst` and has a length of
+    ///   `count * size_of::<T>()` 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<T>(x: &mut T, y: &mut T) {
+    /// /// Moves all the elements of `src` into `dst`, leaving `src` empty.
+    /// fn append<T>(dst: &mut Vec<T>, src: &mut Vec<T>) {
+    ///     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<T>(src: *const T, dst: *mut T, count: usize);
 
-    /// Copies `count * size_of<T>` bytes from `src` to `dst`. The source
+    /// Copies `count * size_of::<T>()` 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::<T>()` bytes must be *both* valid and initialized.
+    ///
+    /// * The region of memory which begins at `dst` and has a length of
+    ///   `count * size_of::<T>()` 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
     ///
     ///     dst
     /// }
     /// ```
-    ///
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn copy<T>(src: *const T, dst: *mut T, count: usize);
 
-    /// Invokes memset on the specified pointer, setting `count * size_of::<T>()`
-    /// bytes of memory starting at `dst` to `val`.
+    /// Sets `count * size_of::<T>()` 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;
     ///
     /// }
     /// 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<T>` with
+    ///     // a null pointer.
+    ///     ptr::write_bytes(&mut v, 0, mem::size_of::<Box<i32>>());
+    /// }
+    ///
+    /// // At this point, using or dropping `v` results in undefined behavior.
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
 
index 5a54de06b5ef2bf55cd99509d1233582a5996db4..98d5030477b51814d119a1cd4f4d72a8b9c9a801 100644 (file)
@@ -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).*
 
 
 /// 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<T>() -> *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<T>(dest: *mut T, mut src: T) -> T {
@@ -260,14 +355,29 @@ pub unsafe fn replace<T>(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<T>(dest: *mut T, mut src: T) -> T {
 ///     assert_eq!(std::ptr::read(y), 12);
 /// }
 /// ```
+///
+/// Manually implement [`mem::swap`]:
+///
+/// ```
+/// use std::ptr;
+///
+/// fn swap<T>(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<T>(src: *const T) -> T {
@@ -292,28 +440,66 @@ pub unsafe fn read<T>(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<T>(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<T>(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<T>(src: *const T) -> T {
 ///     assert_eq!(std::ptr::read(y), 12);
 /// }
 /// ```
+///
+/// Manually implement [`mem::swap`]:
+///
+/// ```
+/// use std::ptr;
+///
+/// fn swap<T>(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<T>(dst: *mut T, src: T) {
@@ -367,36 +590,65 @@ pub unsafe fn write<T>(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<T>(dst: *mut T, src: T) {
@@ -429,12 +681,28 @@ pub unsafe fn write_unaligned<T>(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<T>(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<T>(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
 ///