diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 7756a6f71dbd6..fc996b3677942 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -962,59 +962,129 @@ 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. + /// Behavior is undefined if any of the following conditions are violated: + /// + /// * Both `src` and `dst` must be [valid]. + /// + /// * Both `src` and `dst` must be properly aligned. + /// + /// * `src.offset(count)` must be [valid]. 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(count)` must be [valid]. 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. + /// + /// 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 + /// [violate memory safety][read-ownership]. + /// + /// [`Copy`]: ../marker/trait.Copy.html + /// [`read`]: ../ptr/fn.read.html + /// [read-ownership]: ../ptr/fn.read.html#ownership-of-the-returned-value + /// [valid]: ../ptr/index.html#safety /// /// # 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`]: ../../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); - /// 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. + /// Behavior is undefined if any of the following conditions are violated: + /// + /// * Both `src` and `dst` must be [valid]. + /// + /// * Both `src` and `dst` must be properly aligned. + /// + /// * `src.offset(count)` must be [valid]. 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(count)` must be [valid]. 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 + /// [violate memory safety][read-ownership]. + /// + /// [`Copy`]: ../marker/trait.Copy.html + /// [`read`]: ../ptr/fn.read.html + /// [read-ownership]: ../ptr/fn.read.html#ownership-of-the-returned-value + /// [valid]: ../ptr/index.html#safety /// /// # Examples /// @@ -1031,24 +1101,66 @@ 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 similar to C's [`memset`], but sets `count * + /// size_of::()` bytes to `val`. + /// + /// [`memset`]: https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html#index-memset + /// + /// # Safety + /// + /// Behavior is undefined if any of the following conditions are violated: + /// + /// * `dst` must be [valid]. + /// + /// * `dst.offset(count)` must be [valid]. 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 + /// value of `T`. Creating an invalid value of `T` can result in undefined + /// behavior. + /// + /// [valid]: ../ptr/index.html#safety /// /// # Examples /// + /// Basic usage: + /// /// ``` /// use std::ptr; /// - /// let mut vec = vec![0; 4]; + /// let mut vec = vec![0u32; 4]; /// unsafe { /// let vec_ptr = vec.as_mut_ptr(); - /// ptr::write_bytes(vec_ptr, b'a', 2); + /// ptr::write_bytes(vec_ptr, 0xfe, 2); /// } - /// assert_eq!(vec, [b'a', b'a', 0, 0]); + /// assert_eq!(vec, [0xfefefefe, 0xfefefefe, 0, 0]); + /// ``` + /// + /// Creating an invalid value: + /// + /// ```no_run + /// 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, 1); + /// } + /// + /// // 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); diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 57351822cc3cf..66a06254ef246 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -10,9 +10,24 @@ // FIXME: talk about offset, copy_memory, copy_nonoverlapping_memory -//! Raw, unsafe pointers, `*const T`, and `*mut T`. +//! Manually manage memory through raw pointers. //! //! *[See also the pointer primitive types](../../std/primitive.pointer.html).* +//! +//! # Safety +//! +//! Most functions in this module [dereference raw pointers]. +//! +//! In order for a pointer dereference to be safe, the pointer must be "valid". +//! A valid pointer is one that satisfies **all** of the following conditions: +//! +//! * The pointer is not null. +//! * The pointer is not dangling (it does not point to memory which has been +//! freed). +//! * The pointer satisfies [LLVM's pointer aliasing rules]. +//! +//! [dereference raw pointers]: https://doc.rust-lang.org/book/second-edition/ch19-01-unsafe-rust.html#dereferencing-a-raw-pointer +//! [LLVM's pointer aliasing rules]: https://llvm.org/docs/LangRef.html#pointer-aliasing-rules #![stable(feature = "rust1", since = "1.0.0")] @@ -38,21 +53,63 @@ 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`]: ../ptr/fn.read.html +/// /// # Safety /// -/// This has all the same safety problems as `ptr::read` with respect to -/// invalid pointers, types, and double drops. +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `to_drop` must be [valid]. +/// +/// * `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. +/// +/// [valid]: ../ptr/index.html#safety +/// [`Copy`]: ../marker/trait.Copy.html +/// [`write`]: ../ptr/fn.write.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 +150,27 @@ 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. +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * Both `x` and `y` must be [valid]. /// -/// Ensure that these pointers are valid before calling `swap`. +/// * Both `x` and `y` must be properly aligned. +/// +/// [valid]: ../ptr/index.html#safety /// /// # Examples /// @@ -256,10 +323,38 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { /// /// Neither value is dropped. /// +/// 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. +/// +/// [`mem::replace`]: ../mem/fn.replace.html +/// /// # Safety /// -/// This is only unsafe because it accepts a raw pointer. -/// Otherwise, this operation is identical to `mem::replace`. +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `dest` must be [valid]. +/// +/// * `dest` must be properly aligned. +/// +/// [valid]: ../ptr/index.html#safety +/// +/// # 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 rust[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 { @@ -272,14 +367,52 @@ 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`. +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `src` must be [valid]. +/// +/// * `src` must be properly aligned. Use [`read_unaligned`] if this is not the +/// case. +/// +/// ## Ownership of the Returned Value +/// +/// `read` creates a bitwise copy of `T`, regardless of whether `T` is [`Copy`]. +/// If `T` is not [`Copy`], using both the returned value and the value at +/// `*src` can violate memory safety. Note that assigning to `src` counts as a +/// use because it will attempt to drop the value at `*src`. +/// +/// [`write`] can be used to overwrite data without causing it to be dropped. +/// +/// [valid]: ../ptr/index.html#safety +/// [`Copy`]: ../marker/trait.Copy.html +/// [`read_unaligned`]: ./fn.read_unaligned.html +/// [`write`]: ./fn.write.html +/// +/// ``` +/// use std::ptr; +/// +/// let mut s = String::new("foo"); +/// unsafe { +/// // `s2` now points to the same underlying memory as `s1`. +/// let mut s2 = ptr::read(&s); +/// +/// assert_eq!(s2, "foo"); +/// +/// // Assigning to `s2` causes its original value to be dropped. Beyond +/// // this point, `s` must no longer be used, as the underlying memory has +/// // been freed. +/// s2 = String::default(); /// -/// The pointer must be aligned; use `read_unaligned` if that is not the case. +/// // Assigning to `s` would cause the old value to be dropped again, +/// // resulting in undefined behavior. +/// // s = String::new("bar"); // ERROR +/// +/// // `ptr::write` can be used to overwrite a value without dropping it. +/// ptr::write(&s, String::new("bar")); +/// } +/// +/// assert_eq!(s, "bar"); +/// ``` /// /// # Examples /// @@ -293,6 +426,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 { @@ -304,28 +475,59 @@ 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 /// -/// 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`. +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `src` must be [valid]. +/// +/// 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 +/// value and the value at `*src` can [violate memory safety][read-ownership]. +/// +/// [`Copy`]: ../marker/trait.Copy.html +/// [`read`]: ./fn.read.html +/// [`write_unaligned`]: ./fn.write_unaligned.html +/// [read-ownership]: ./fn.read.html#ownership-of-the-returned-value +/// [valid]: ../ptr/index.html#safety /// /// # 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")] @@ -340,11 +542,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. /// @@ -352,9 +550,21 @@ 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. /// -/// The pointer must be aligned; use `write_unaligned` if that is not the case. +/// [`read`]: ./fn.read.html +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `dst` must be [valid]. +/// +/// * `dst` must be properly aligned. Use [`write_unaligned`] if this is not the +/// case. +/// +/// [valid]: ../ptr/index.html#safety +/// [`write_unaligned`]: ./fn.write_unaligned.html /// /// # Examples /// @@ -370,6 +580,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) { @@ -379,36 +613,60 @@ 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. -/// -/// # Safety +/// Unlike [`write`], the pointer may be unaligned. /// -/// 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 with [`read_unaligned`]. +/// +/// [`write`]: ./fn.write.html +/// [`read_unaligned`]: ./fn.read_unaligned.html +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `dst` must be [valid]. +/// +/// [valid]: ../ptr/index.html#safety /// /// # 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) { @@ -425,6 +683,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, @@ -441,12 +704,21 @@ 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`. +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `src` must be [valid]. +/// +/// * `src` must be properly aligned. +/// +/// 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 +/// value and the value at `*src` can [violate memory safety][read-ownership]. +/// However, storing non-[`Copy`] types in volatile memory is almost certainly +/// incorrect. +/// +/// [valid]: ../ptr/index.html#safety +/// [`Copy`]: ../marker/trait.Copy.html +/// [`read`]: ./fn.read.html /// /// Just like in C, whether an operation is volatile has no bearing whatsoever /// on questions involving concurrent access from multiple threads. Volatile @@ -479,6 +751,18 @@ 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. +/// +/// 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, @@ -495,14 +779,13 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// /// # Safety /// -/// This operation is marked unsafe because it accepts a raw pointer. +/// Behavior is undefined if any of the following conditions are violated: /// -/// 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. +/// * `dst` must be [valid]. /// -/// This is appropriate for initializing uninitialized memory, or overwriting -/// memory that has previously been `read` from. +/// * `dst` must be properly aligned. +/// +/// [valid]: ../ptr/index.html#safety /// /// Just like in C, whether an operation is volatile has no bearing whatsoever /// on questions involving concurrent access from multiple threads. Volatile