From 911d35f0bfd207112806eaec2763201dad06d1c7 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Fri, 6 Apr 2018 00:34:45 -0700 Subject: [PATCH 01/33] 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 invariants which, when violated, cause 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 - Define what constitutes a "valid" pointer. - Centralize discussion of ownership of bitwise copies in `ptr::read` and provide an example. --- src/libcore/intrinsics.rs | 180 ++++++++++++---- src/libcore/ptr.rs | 419 +++++++++++++++++++++++++++++++------- 2 files changed, 497 insertions(+), 102 deletions(-) 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 From da58bebf01b1213cde5490adc5c476f87c3ae423 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 23 May 2018 20:55:39 -0700 Subject: [PATCH 02/33] Mention alignment in top-level docs This also removes the overlong link that failed tidy xD. --- src/libcore/ptr.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 66a06254ef246..3faadca3f3937 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -16,18 +16,23 @@ //! //! # 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: +//! Many functions in this module take raw pointers as arguments and dereference +//! them. For this to be safe, these pointers 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 +//! Valid pointers are not necessarily properly aligned. However, except for +//! [`read_unaligned`] and [`write_unaligned`], most functions require their +//! arguments to be aligned. Any alignment requirements will be explicitly +//! stated in the function's documentation. +//! //! [LLVM's pointer aliasing rules]: https://llvm.org/docs/LangRef.html#pointer-aliasing-rules +//! [`read_unaligned`]: ./fn.read_unaligned.html +//! [`write_unaligned`]: ./fn.write_unaligned.html #![stable(feature = "rust1", since = "1.0.0")] @@ -667,6 +672,7 @@ pub unsafe fn write(dst: *mut T, src: T) { /// /// // 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) { From 9f5a3cccb8a2ca59ea43421d357bf57dd954249c Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 23 May 2018 22:38:22 -0700 Subject: [PATCH 03/33] Fix failing doctests --- src/libcore/intrinsics.rs | 2 +- src/libcore/ptr.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index fc996b3677942..1c400cbdfcb39 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1149,7 +1149,7 @@ extern "rust-intrinsic" { /// Creating an invalid value: /// /// ```no_run - /// use std::{mem, ptr}; + /// use std::ptr; /// /// let mut v = Box::new(0i32); /// diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 3faadca3f3937..eaff309376762 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -396,7 +396,7 @@ pub unsafe fn replace(dest: *mut T, mut src: T) -> T { /// ``` /// use std::ptr; /// -/// let mut s = String::new("foo"); +/// let mut s = String::from("foo"); /// unsafe { /// // `s2` now points to the same underlying memory as `s1`. /// let mut s2 = ptr::read(&s); @@ -410,10 +410,10 @@ pub unsafe fn replace(dest: *mut T, mut src: T) -> T { /// /// // Assigning to `s` would cause the old value to be dropped again, /// // resulting in undefined behavior. -/// // s = String::new("bar"); // ERROR +/// // s = String::from("bar"); // ERROR /// /// // `ptr::write` can be used to overwrite a value without dropping it. -/// ptr::write(&s, String::new("bar")); +/// ptr::write(&mut s, String::from("bar")); /// } /// /// assert_eq!(s, "bar"); From 04a08c60a193e81bc82fa6af05dc4d7e5371e0ab Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Thu, 24 May 2018 09:05:56 -0700 Subject: [PATCH 04/33] Fix unused variable warning in doctest --- src/libcore/ptr.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index eaff309376762..e02ee09c8af00 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -407,6 +407,7 @@ pub unsafe fn replace(dest: *mut T, mut src: T) -> T { /// // this point, `s` must no longer be used, as the underlying memory has /// // been freed. /// s2 = String::default(); +/// assert_eq!(s2, ""); /// /// // Assigning to `s` would cause the old value to be dropped again, /// // resulting in undefined behavior. From 7b2ef6bd771b2624f0e5f889277190d13c437414 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 28 May 2018 17:41:19 -0700 Subject: [PATCH 05/33] Update docs for `swap_nonoverlapping` They closely mirror the docs for `copy_nonoverlapping` --- src/libcore/ptr.rs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index e02ee09c8af00..ae7ff78b29130 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -226,12 +226,28 @@ pub unsafe fn swap(x: *mut T, y: *mut T) { mem::forget(tmp); } -/// Swaps a sequence of values at two mutable locations of the same type. +/// Swaps `count * size_of::()` bytes between the two regions of memory +/// beginning at `x` and `y`. The two regions must *not* overlap. /// /// # Safety /// -/// The two arguments must each point to the beginning of `count` locations -/// of valid memory, and the two memory ranges must not overlap. +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * Both `x` and `y` must be [valid]. +/// +/// * Both `x` and `y` must be properly aligned. +/// +/// * `x.offset(count)` must be [valid]. In other words, the region of memory +/// which begins at `x` and has a length of `count * size_of::()` bytes +/// must belong to a single, live allocation. +/// +/// * `y.offset(count)` must be [valid]. In other words, the region of memory +/// which begins at `y` and has a length of `count * size_of::()` bytes +/// must belong to a single, live allocation. +/// +/// * The two regions of memory must *not* overlap. +/// +/// [valid]: ../ptr/index.html#safety /// /// # Examples /// From 6f7338bb9246abc5078529e218fded18e8766926 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Tue, 5 Jun 2018 11:22:40 -0700 Subject: [PATCH 06/33] Reword module level docs re: alignment --- src/libcore/ptr.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index ae7ff78b29130..f15ad7c05cb13 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -25,10 +25,10 @@ //! freed). //! * The pointer satisfies [LLVM's pointer aliasing rules]. //! -//! Valid pointers are not necessarily properly aligned. However, except for -//! [`read_unaligned`] and [`write_unaligned`], most functions require their -//! arguments to be aligned. Any alignment requirements will be explicitly -//! stated in the function's documentation. +//! Valid pointers are not necessarily properly aligned. However, most functions +//! require their arguments to be properly aligned, and will explicitly state +//! this requirement in the `Safety` section. Notable exceptions to this are +//! [`read_unaligned`] and [`write_unaligned`]. //! //! [LLVM's pointer aliasing rules]: https://llvm.org/docs/LangRef.html#pointer-aliasing-rules //! [`read_unaligned`]: ./fn.read_unaligned.html From 30122e91d95e63dc47063b3b596c72ba65eec0a1 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Tue, 5 Jun 2018 13:17:24 -0700 Subject: [PATCH 07/33] Fix off-by-one error when specifying a valid range --- src/libcore/intrinsics.rs | 10 +++++----- src/libcore/ptr.rs | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 1c400cbdfcb39..ba16715a6b88f 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -980,11 +980,11 @@ extern "rust-intrinsic" { /// /// * Both `src` and `dst` must be properly aligned. /// - /// * `src.offset(count)` must be [valid]. In other words, the region of + /// * `src.offset(count-1)` 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 + /// * `dst.offset(count-1)` 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. /// @@ -1068,11 +1068,11 @@ extern "rust-intrinsic" { /// /// * Both `src` and `dst` must be properly aligned. /// - /// * `src.offset(count)` must be [valid]. In other words, the region of + /// * `src.offset(count-1)` 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 + /// * `dst.offset(count-1)` 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. /// @@ -1118,7 +1118,7 @@ extern "rust-intrinsic" { /// /// * `dst` must be [valid]. /// - /// * `dst.offset(count)` must be [valid]. In other words, the region of + /// * `dst.offset(count-1)` 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. /// diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index f15ad7c05cb13..a28b3422d1b4e 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -237,11 +237,11 @@ pub unsafe fn swap(x: *mut T, y: *mut T) { /// /// * Both `x` and `y` must be properly aligned. /// -/// * `x.offset(count)` must be [valid]. In other words, the region of memory +/// * `x.offset(count-1)` must be [valid]. In other words, the region of memory /// which begins at `x` and has a length of `count * size_of::()` bytes /// must belong to a single, live allocation. /// -/// * `y.offset(count)` must be [valid]. In other words, the region of memory +/// * `y.offset(count-1)` must be [valid]. In other words, the region of memory /// which begins at `y` and has a length of `count * size_of::()` bytes /// must belong to a single, live allocation. /// From e40585f2483b6aabe0107662727c906839717555 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Fri, 15 Jun 2018 16:00:07 -0700 Subject: [PATCH 08/33] Remove definiton of valid pointer The enumerated list of conditions is replaced by an explanation that rust doesn't have a formal memory model. It does say that pointers created directly from references are guaranteed to be valid, and links to both the "Unsafe Code" section of the book and the "Undefined Behavior" section of the reference. --- src/libcore/ptr.rs | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index a28b3422d1b4e..dd27bc715fa90 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -17,20 +17,27 @@ //! # Safety //! //! Many functions in this module take raw pointers as arguments and dereference -//! them. For this to be safe, these pointers must be valid. A valid pointer -//! is one that satisfies **all** of the following conditions: +//! them. For this to be safe, these pointers must be valid. However, because +//! rust does not yet have a formal memory model, determining whether an +//! arbitrary pointer is a valid one can be tricky. One thing is certain: +//! creating a raw pointer from a reference (e.g. `&x as *const _`) *always* +//! results in a valid pointer. By exploiting this—and by taking care when +//! using [pointer arithmetic]—users can be confident in the correctness of +//! their unsafe code. //! -//! * 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]. +//! For more information on dereferencing raw pointers, see the both the [book] +//! and the section in the reference devoted to [undefined behavior][ub]. +//! +//! ## Alignment //! //! Valid pointers are not necessarily properly aligned. However, most functions //! require their arguments to be properly aligned, and will explicitly state //! this requirement in the `Safety` section. Notable exceptions to this are //! [`read_unaligned`] and [`write_unaligned`]. //! -//! [LLVM's pointer aliasing rules]: https://llvm.org/docs/LangRef.html#pointer-aliasing-rules +//! [ub]: ../../reference/behavior-considered-undefined.html +//! [book]: ../../book/second-edition/ch19-01-unsafe-rust.html#dereferencing-a-raw-pointer +//! [pointer arithmetic]: ../../std/primitive.pointer.html#method.offset //! [`read_unaligned`]: ./fn.read_unaligned.html //! [`write_unaligned`]: ./fn.write_unaligned.html From ea5570cf277601f479a0a5fc8e65adfac60d2922 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Fri, 15 Jun 2018 22:33:00 -0700 Subject: [PATCH 09/33] Redefine range validity Uses `x.offset(i)` must be valid for all `i` in `0..count`. --- src/libcore/intrinsics.rs | 43 +++++++++++++++++++-------------------- src/libcore/ptr.rs | 14 ++++++------- 2 files changed, 27 insertions(+), 30 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index ba16715a6b88f..43dcc180b8623 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -976,17 +976,17 @@ extern "rust-intrinsic" { /// /// 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-1)` 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. + /// * `src.offset(i)` must be [valid] for all `i` in `0..count`. In other + /// words, the region of memory which begins at `src` and has a length of + /// `count * size_of::()` bytes must belong to a single, live + /// allocation. /// - /// * `dst.offset(count-1)` 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.offset(i)` must be [valid] for all `i` in `0..count`. In other + /// words, the region of memory which begins at `dst` and has a length of + /// `count * size_of::()` bytes must belong to a single, live + /// allocation. /// /// * The two regions of memory must *not* overlap. /// @@ -1064,17 +1064,17 @@ extern "rust-intrinsic" { /// /// 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-1)` 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. + /// * `src.offset(i)` must be [valid] for all `i` in `0..count`. In other + /// words, the region of memory which begins at `src` and has a length of + /// `count * size_of::()` bytes must belong to a single, live + /// allocation. /// - /// * `dst.offset(count-1)` 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.offset(i)` must be [valid] for all `i` in `0..count`. In other + /// words, the region of memory which begins at `dst` and has a length of + /// `count * size_of::()` bytes must belong to a single, live + /// allocation. /// /// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of /// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values @@ -1116,14 +1116,13 @@ extern "rust-intrinsic" { /// /// Behavior is undefined if any of the following conditions are violated: /// - /// * `dst` must be [valid]. - /// - /// * `dst.offset(count-1)` 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. /// + /// * `dst.offset(i)` must be [valid] for all `i` in `0..count`. In other + /// words, the region of memory which begins at `dst` and has a length of + /// `count * size_of::()` bytes must belong to a single, live + /// allocation. + /// /// 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 diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index dd27bc715fa90..7cbb4462d06d8 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -240,17 +240,15 @@ pub unsafe fn swap(x: *mut T, y: *mut T) { /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * Both `x` and `y` must be [valid]. -/// /// * Both `x` and `y` must be properly aligned. /// -/// * `x.offset(count-1)` must be [valid]. In other words, the region of memory -/// which begins at `x` and has a length of `count * size_of::()` bytes -/// must belong to a single, live allocation. +/// * `x.offset(i)` must be [valid] for all `i` in `0..count`. In other words, +/// the region of memory which begins at `x` and has a length of `count * +/// size_of::()` bytes must belong to a single, live allocation. /// -/// * `y.offset(count-1)` must be [valid]. In other words, the region of memory -/// which begins at `y` and has a length of `count * size_of::()` bytes -/// must belong to a single, live allocation. +/// * `y.offset(i)` must be [valid] for all `i` in `0..count`. In other words, +/// the region of memory which begins at `y` and has a length of `count * +/// size_of::()` bytes must belong to a single, live allocation. /// /// * The two regions of memory must *not* overlap. /// From 3a55c85c33ec1ed5222ff7f9c57ce8fc426d9455 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sun, 17 Jun 2018 02:45:38 -0700 Subject: [PATCH 10/33] Incorporate RalfJung's suggestions This splits "valid" into "valid for reads" and "valid for writes", and also adds the concept of operation size to validity. Now functions which operate on sequences state that e.g. pointer args must be "valid for reads of size x". --- src/libcore/intrinsics.rs | 35 +++++++-------------- src/libcore/ptr.rs | 66 ++++++++++++++++++++++----------------- 2 files changed, 49 insertions(+), 52 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 43dcc180b8623..b9b086db01069 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -976,19 +976,15 @@ extern "rust-intrinsic" { /// /// Behavior is undefined if any of the following conditions are violated: /// - /// * Both `src` and `dst` must be properly aligned. + /// * `src` must be [valid] for reads of `count * size_of::()` bytes. /// - /// * `src.offset(i)` must be [valid] for all `i` in `0..count`. In other - /// words, the region of memory which begins at `src` and has a length of - /// `count * size_of::()` bytes must belong to a single, live - /// allocation. + /// * `dst` must be [valid] for writes of `count * size_of::()` bytes. /// - /// * `dst.offset(i)` must be [valid] for all `i` in `0..count`. In other - /// words, the region of memory which begins at `dst` and has a length of - /// `count * size_of::()` bytes must belong to a single, live - /// allocation. + /// * Both `src` and `dst` must be properly aligned. /// - /// * The two regions of memory must *not* overlap. + /// * The region of memory beginning at `src` with a size of `count * + /// size_of::()` bytes must *not* overlap with the region of memory + /// beginning at `dst` with the same size. /// /// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of /// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values @@ -1064,17 +1060,11 @@ extern "rust-intrinsic" { /// /// Behavior is undefined if any of the following conditions are violated: /// - /// * Both `src` and `dst` must be properly aligned. + /// * `src` must be [valid] for reads of `count * size_of::()` bytes. /// - /// * `src.offset(i)` must be [valid] for all `i` in `0..count`. In other - /// words, the region of memory which begins at `src` and has a length of - /// `count * size_of::()` bytes must belong to a single, live - /// allocation. + /// * `dst` must be [valid] for writes of `count * size_of::()` bytes. /// - /// * `dst.offset(i)` must be [valid] for all `i` in `0..count`. In other - /// words, the region of memory which begins at `dst` and has a length of - /// `count * size_of::()` bytes must belong to a single, live - /// allocation. + /// * Both `src` and `dst` must be properly aligned. /// /// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of /// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values @@ -1116,12 +1106,9 @@ extern "rust-intrinsic" { /// /// Behavior is undefined if any of the following conditions are violated: /// - /// * `dst` must be properly aligned. + /// * `dst` must be [valid] for writes of `count * size_of::()` bytes. /// - /// * `dst.offset(i)` must be [valid] for all `i` in `0..count`. In other - /// words, the region of memory which begins at `dst` and has a length of - /// `count * size_of::()` bytes must belong to a single, live - /// allocation. + /// * `dst` must be properly aligned. /// /// Additionally, the caller must ensure that writing `count * /// size_of::()` bytes to the given region of memory results in a valid diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 7cbb4462d06d8..ee209b9ccca70 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -19,25 +19,38 @@ //! Many functions in this module take raw pointers as arguments and dereference //! them. For this to be safe, these pointers must be valid. However, because //! rust does not yet have a formal memory model, determining whether an -//! arbitrary pointer is a valid one can be tricky. One thing is certain: -//! creating a raw pointer from a reference (e.g. `&x as *const _`) *always* -//! results in a valid pointer. By exploiting this—and by taking care when -//! using [pointer arithmetic]—users can be confident in the correctness of -//! their unsafe code. +//! arbitrary pointer is valid for a given operation can be tricky. //! -//! For more information on dereferencing raw pointers, see the both the [book] -//! and the section in the reference devoted to [undefined behavior][ub]. +//! There are two types of operations on memory, reads and writes. It is +//! possible for a `*mut` to be valid for one operation and not the other. Since +//! a `*const` can only be read and not written, it has no such ambiguity. For +//! example, a `*mut` is not valid for writes if a a reference exists which +//! [refers to the same memory][aliasing]. Therefore, each function in this +//! module will document which operations must be valid on any `*mut` arguments. +//! +//! Additionally, some functions (e.g. [`copy`]) take a single pointer but +//! operate on many values. In this case, the function will state the size of +//! the operation for which the pointer must be valid. For example, +//! `copy::(&src, &mut dst, 3)` requires `dst` to be valid for writes of +//! `size_of::() * 3` bytes. When the documentation requires that a pointer +//! be valid for an operation but omits the size of that operation, the size is +//! implied to be `size_of::()` bytes. +//! +//! For more information on the safety implications of dereferencing raw +//! pointers, see the both the [book] and the section in the reference devoted +//! to [undefined behavior][ub]. //! //! ## Alignment //! //! Valid pointers are not necessarily properly aligned. However, most functions //! require their arguments to be properly aligned, and will explicitly state -//! this requirement in the `Safety` section. Notable exceptions to this are +//! this requirement in their documentation. Notable exceptions to this are //! [`read_unaligned`] and [`write_unaligned`]. //! -//! [ub]: ../../reference/behavior-considered-undefined.html +//! [aliasing]: ../../nomicon/aliasing.html //! [book]: ../../book/second-edition/ch19-01-unsafe-rust.html#dereferencing-a-raw-pointer -//! [pointer arithmetic]: ../../std/primitive.pointer.html#method.offset +//! [ub]: ../../reference/behavior-considered-undefined.html +//! [`copy`]: ./fn.copy.html //! [`read_unaligned`]: ./fn.read_unaligned.html //! [`write_unaligned`]: ./fn.write_unaligned.html @@ -83,7 +96,7 @@ pub use intrinsics::write_bytes; /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * `to_drop` must be [valid]. +/// * `to_drop` must be [valid] for reads. /// /// * `to_drop` must be properly aligned. /// @@ -178,7 +191,7 @@ pub const fn null_mut() -> *mut T { 0 as *mut T } /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * Both `x` and `y` must be [valid]. +/// * Both `x` and `y` must be [valid] for reads and writes. /// /// * Both `x` and `y` must be properly aligned. /// @@ -240,17 +253,14 @@ pub unsafe fn swap(x: *mut T, y: *mut T) { /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * Both `x` and `y` must be properly aligned. -/// -/// * `x.offset(i)` must be [valid] for all `i` in `0..count`. In other words, -/// the region of memory which begins at `x` and has a length of `count * -/// size_of::()` bytes must belong to a single, live allocation. +/// * Both `x` and `y` must be [valid] for reads and writes of `count * +/// size_of::()` bytes. /// -/// * `y.offset(i)` must be [valid] for all `i` in `0..count`. In other words, -/// the region of memory which begins at `y` and has a length of `count * -/// size_of::()` bytes must belong to a single, live allocation. +/// * Both `x` and `y` must be properly aligned. /// -/// * The two regions of memory must *not* overlap. +/// * The region of memory beginning at `x` with a size of `count * +/// size_of::()` bytes must *not* overlap with the region of memory +/// beginning at `y` with the same size. /// /// [valid]: ../ptr/index.html#safety /// @@ -359,7 +369,7 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * `dest` must be [valid]. +/// * `dest` must be [valid] for writes. /// /// * `dest` must be properly aligned. /// @@ -395,7 +405,7 @@ pub unsafe fn replace(dest: *mut T, mut src: T) -> T { /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * `src` must be [valid]. +/// * `src` must be [valid] for reads. /// /// * `src` must be properly aligned. Use [`read_unaligned`] if this is not the /// case. @@ -508,7 +518,7 @@ pub unsafe fn read(src: *const T) -> T { /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * `src` must be [valid]. +/// * `src` must be [valid] for reads. /// /// Like [`read`], `read_unaligned` creates a bitwise copy of `T`, regardless of /// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the returned @@ -585,7 +595,7 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * `dst` must be [valid]. +/// * `dst` must be [valid] for writes. /// /// * `dst` must be properly aligned. Use [`write_unaligned`] if this is not the /// case. @@ -659,7 +669,7 @@ pub unsafe fn write(dst: *mut T, src: T) { /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * `dst` must be [valid]. +/// * `dst` must be [valid] for writes. /// /// [valid]: ../ptr/index.html#safety /// @@ -734,7 +744,7 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * `src` must be [valid]. +/// * `src` must be [valid] for reads. /// /// * `src` must be properly aligned. /// @@ -809,7 +819,7 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * `dst` must be [valid]. +/// * `dst` must be [valid] for writes. /// /// * `dst` must be properly aligned. /// From 95a9088603368fb8f80a1841bc8ddb20509cfd45 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sun, 17 Jun 2018 10:44:29 -0700 Subject: [PATCH 11/33] You can't make an omlette without breaking a few links --- 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 ee209b9ccca70..c79c0129f1406 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -50,7 +50,7 @@ //! [aliasing]: ../../nomicon/aliasing.html //! [book]: ../../book/second-edition/ch19-01-unsafe-rust.html#dereferencing-a-raw-pointer //! [ub]: ../../reference/behavior-considered-undefined.html -//! [`copy`]: ./fn.copy.html +//! [`copy`]: ../../std/ptr/fn.copy.html //! [`read_unaligned`]: ./fn.read_unaligned.html //! [`write_unaligned`]: ./fn.write_unaligned.html From 7e165d90a6f4dfeb472e6385edc6cd8ef79695a1 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 4 Jul 2018 11:30:23 -0700 Subject: [PATCH 12/33] Add a list of known facts re: validity Also rewrites the reads/writes section to be less reliant on `*const`, `*mut` --- src/libcore/ptr.rs | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index c79c0129f1406..7687f16b4ce49 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -21,14 +21,15 @@ //! rust does not yet have a formal memory model, determining whether an //! arbitrary pointer is valid for a given operation can be tricky. //! -//! There are two types of operations on memory, reads and writes. It is -//! possible for a `*mut` to be valid for one operation and not the other. Since -//! a `*const` can only be read and not written, it has no such ambiguity. For -//! example, a `*mut` is not valid for writes if a a reference exists which -//! [refers to the same memory][aliasing]. Therefore, each function in this -//! module will document which operations must be valid on any `*mut` arguments. +//! There are two types of operations on memory, reads and writes. A single +//! pointer can be valid for any combination of these operations. For example, a +//! pointer is not valid for writes if a `&mut` exists which [refers to the same +//! memory][aliasing]. The set of operations for which a pointer argument must +//! be valid is explicitly documented for each function. This is not strictly +//! necessary for `*const` arguments, as they can only be used for reads and +//! never for writes. //! -//! Additionally, some functions (e.g. [`copy`]) take a single pointer but +//! Some functions (e.g. [`copy`]) take a single pointer but //! operate on many values. In this case, the function will state the size of //! the operation for which the pointer must be valid. For example, //! `copy::(&src, &mut dst, 3)` requires `dst` to be valid for writes of @@ -36,8 +37,21 @@ //! be valid for an operation but omits the size of that operation, the size is //! implied to be `size_of::()` bytes. //! -//! For more information on the safety implications of dereferencing raw -//! pointers, see the both the [book] and the section in the reference devoted +//! While we can't yet define whether an arbitrary pointer is a valid one, there +//! are a few rules regarding validity: +//! +//! * The result of casting a reference to a pointer is valid for as long as the +//! underlying object is live. +//! * All pointers to types with a [size of zero][zst] are valid for all +//! operations of size zero. +//! * A [null] pointer is *never* valid, except when it points to a zero-sized +//! type. +//! +//! These axioms, along with careful use of [`offset`] for pointer arithmentic, +//! are enough to correctly implement many useful things in unsafe code. Still, +//! unsafe code should be carefully examined since some of the finer +//! details—notably the [aliasing] rules—are not yet settled. For more +//! information, see the [book] as well as the section in the reference devoted //! to [undefined behavior][ub]. //! //! ## Alignment @@ -50,7 +64,10 @@ //! [aliasing]: ../../nomicon/aliasing.html //! [book]: ../../book/second-edition/ch19-01-unsafe-rust.html#dereferencing-a-raw-pointer //! [ub]: ../../reference/behavior-considered-undefined.html +//! [null]: ./fn.null.html +//! [zst]: ../../nomicon/exotic-sizes.html#zero-sized-types-zsts //! [`copy`]: ../../std/ptr/fn.copy.html +//! [`offset`]: ../../std/primitive.pointer.html#method.offset //! [`read_unaligned`]: ./fn.read_unaligned.html //! [`write_unaligned`]: ./fn.write_unaligned.html From c8da32158189118790e64873be6493cfdedbeac1 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 4 Jul 2018 12:02:26 -0700 Subject: [PATCH 13/33] Resolve null/ZST conflict correctly (whoops) --- src/libcore/ptr.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 7687f16b4ce49..1d8c3696b4592 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -42,10 +42,9 @@ //! //! * The result of casting a reference to a pointer is valid for as long as the //! underlying object is live. -//! * All pointers to types with a [size of zero][zst] are valid for all -//! operations of size zero. -//! * A [null] pointer is *never* valid, except when it points to a zero-sized -//! type. +//! * A [null] pointer is *never* valid. +//! * All pointers (except for the null pointer) are valid for all operations of +//! [size zero][zst]. //! //! These axioms, along with careful use of [`offset`] for pointer arithmentic, //! are enough to correctly implement many useful things in unsafe code. Still, From b0c5dc2cc1f186f0ab7a883d12b1cac84a0fab10 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 Aug 2018 14:34:59 +0200 Subject: [PATCH 14/33] edit docs a little --- src/libcore/intrinsics.rs | 15 ++++++++-- src/libcore/ptr.rs | 61 ++++++++++++++++++++++++--------------- 2 files changed, 49 insertions(+), 27 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index b9b086db01069..9748feddddff7 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -986,11 +986,14 @@ extern "rust-intrinsic" { /// size_of::()` bytes must *not* overlap with the region of memory /// beginning at `dst` with the same size. /// - /// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of - /// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values + /// Like [`read`], `copy_nonoverlapping` 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]. /// + /// These restrictions apply even if the effectively copied size (`count * + /// size_of::()`) is `0`. + /// /// [`Copy`]: ../marker/trait.Copy.html /// [`read`]: ../ptr/fn.read.html /// [read-ownership]: ../ptr/fn.read.html#ownership-of-the-returned-value @@ -1071,6 +1074,9 @@ extern "rust-intrinsic" { /// in the region beginning at `*src` and the region beginning at `*dst` can /// [violate memory safety][read-ownership]. /// + /// These restrictions apply even if the effectively copied size (`count * + /// size_of::()`) is `0`. + /// /// [`Copy`]: ../marker/trait.Copy.html /// [`read`]: ../ptr/fn.read.html /// [read-ownership]: ../ptr/fn.read.html#ownership-of-the-returned-value @@ -1115,6 +1121,9 @@ extern "rust-intrinsic" { /// value of `T`. Creating an invalid value of `T` can result in undefined /// behavior. /// + /// These restrictions apply even if the effectively written size (`count * + /// size_of::()`) is `0`. + /// /// [valid]: ../ptr/index.html#safety /// /// # Examples @@ -1164,7 +1173,7 @@ extern "rust-intrinsic" { /// `min_align_of::()` /// /// The volatile parameter is set to `true`, so it will not be optimized out - /// unless size is equal to zero.. + /// unless size is equal to zero. pub fn volatile_copy_memory(dst: *mut T, src: *const T, count: usize); /// Equivalent to the appropriate `llvm.memset.p0i8.*` intrinsic, with a /// size of `count` * `size_of::()` and an alignment of diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 1d8c3696b4592..b82afecd7696c 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -16,35 +16,23 @@ //! //! # Safety //! -//! Many functions in this module take raw pointers as arguments and dereference -//! them. For this to be safe, these pointers must be valid. However, because -//! rust does not yet have a formal memory model, determining whether an -//! arbitrary pointer is valid for a given operation can be tricky. +//! Many functions in this module take raw pointers as arguments and read from +//! or write to them. For this to be safe, these pointers must be *valid*. +//! Whether a pointer is valid depends on the operation it is used for +//! (read or write), and the extent of the memory that is accessed (i.e., +//! how many bytes are read/written). Most functions use `*mut T` and `*const T` +//! to access only a single value, in which case the documentation omits the size +//! and implicitly assumes it to be `size_of::()` bytes. //! -//! There are two types of operations on memory, reads and writes. A single -//! pointer can be valid for any combination of these operations. For example, a -//! pointer is not valid for writes if a `&mut` exists which [refers to the same -//! memory][aliasing]. The set of operations for which a pointer argument must -//! be valid is explicitly documented for each function. This is not strictly -//! necessary for `*const` arguments, as they can only be used for reads and -//! never for writes. -//! -//! Some functions (e.g. [`copy`]) take a single pointer but -//! operate on many values. In this case, the function will state the size of -//! the operation for which the pointer must be valid. For example, -//! `copy::(&src, &mut dst, 3)` requires `dst` to be valid for writes of -//! `size_of::() * 3` bytes. When the documentation requires that a pointer -//! be valid for an operation but omits the size of that operation, the size is -//! implied to be `size_of::()` bytes. -//! -//! While we can't yet define whether an arbitrary pointer is a valid one, there +//! While we can't yet define whether an arbitrary pointer is valid, there //! are a few rules regarding validity: //! -//! * The result of casting a reference to a pointer is valid for as long as the -//! underlying object is live. -//! * A [null] pointer is *never* valid. +//! * A [null] pointer is *never* valid, not even for accesses of [size zero][zst]. //! * All pointers (except for the null pointer) are valid for all operations of //! [size zero][zst]. +//! * The result of casting a reference to a pointer is valid for as long as the +//! underlying object is live and no reference (just raw pointers) is used to +//! access the same memory. //! //! These axioms, along with careful use of [`offset`] for pointer arithmentic, //! are enough to correctly implement many useful things in unsafe code. Still, @@ -60,6 +48,10 @@ //! this requirement in their documentation. Notable exceptions to this are //! [`read_unaligned`] and [`write_unaligned`]. //! +//! When a function requires proper alignment, it does so even if the access +//! has size 0, i.e., even if memory is not actually touched. Consider using +//! [`NonNull::dangling`] in such cases. +//! //! [aliasing]: ../../nomicon/aliasing.html //! [book]: ../../book/second-edition/ch19-01-unsafe-rust.html#dereferencing-a-raw-pointer //! [ub]: ../../reference/behavior-considered-undefined.html @@ -69,6 +61,7 @@ //! [`offset`]: ../../std/primitive.pointer.html#method.offset //! [`read_unaligned`]: ./fn.read_unaligned.html //! [`write_unaligned`]: ./fn.write_unaligned.html +//! [`NonNull::dangling`]: ./struct.NonNull.html#method.dangling #![stable(feature = "rust1", since = "1.0.0")] @@ -122,6 +115,8 @@ pub use intrinsics::write_bytes; /// again. [`write`] can be used to overwrite data without causing it to be /// dropped. /// +/// These restrictions apply even if `T` has size `0`. +/// /// [valid]: ../ptr/index.html#safety /// [`Copy`]: ../marker/trait.Copy.html /// [`write`]: ../ptr/fn.write.html @@ -211,6 +206,8 @@ pub const fn null_mut() -> *mut T { 0 as *mut T } /// /// * Both `x` and `y` must be properly aligned. /// +/// These restrictions apply even if `T` has size `0`. +/// /// [valid]: ../ptr/index.html#safety /// /// # Examples @@ -278,6 +275,8 @@ pub unsafe fn swap(x: *mut T, y: *mut T) { /// size_of::()` bytes must *not* overlap with the region of memory /// beginning at `y` with the same size. /// +/// These restrictions apply even if `T` has size `0`. +/// /// [valid]: ../ptr/index.html#safety /// /// # Examples @@ -389,6 +388,8 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { /// /// * `dest` must be properly aligned. /// +/// These restrictions apply even if `T` has size `0`. +/// /// [valid]: ../ptr/index.html#safety /// /// # Examples @@ -426,6 +427,8 @@ pub unsafe fn replace(dest: *mut T, mut src: T) -> T { /// * `src` must be properly aligned. Use [`read_unaligned`] if this is not the /// case. /// +/// These restrictions apply even if `T` has size `0`. +/// /// ## Ownership of the Returned Value /// /// `read` creates a bitwise copy of `T`, regardless of whether `T` is [`Copy`]. @@ -540,6 +543,8 @@ pub unsafe fn read(src: *const T) -> T { /// 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]. /// +/// These restrictions apply even if `T` has size `0`. +/// /// [`Copy`]: ../marker/trait.Copy.html /// [`read`]: ./fn.read.html /// [`write_unaligned`]: ./fn.write_unaligned.html @@ -616,6 +621,8 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// * `dst` must be properly aligned. Use [`write_unaligned`] if this is not the /// case. /// +/// These restrictions apply even if `T` has size `0`. +/// /// [valid]: ../ptr/index.html#safety /// [`write_unaligned`]: ./fn.write_unaligned.html /// @@ -687,6 +694,8 @@ pub unsafe fn write(dst: *mut T, src: T) { /// /// * `dst` must be [valid] for writes. /// +/// These restrictions apply even if `T` has size `0`. +/// /// [valid]: ../ptr/index.html#safety /// /// # Examples @@ -770,6 +779,8 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// However, storing non-[`Copy`] types in volatile memory is almost certainly /// incorrect. /// +/// These restrictions apply even if `T` has size `0`. +/// /// [valid]: ../ptr/index.html#safety /// [`Copy`]: ../marker/trait.Copy.html /// [`read`]: ./fn.read.html @@ -839,6 +850,8 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// /// * `dst` must be properly aligned. /// +/// These restrictions apply even if `T` has size `0`. +/// /// [valid]: ../ptr/index.html#safety /// /// Just like in C, whether an operation is volatile has no bearing whatsoever From 098bec82f6171c2e7e5b4136880eb52eda876bde Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 Aug 2018 19:27:20 +0200 Subject: [PATCH 15/33] clarify that these are preliminary guarantees --- src/libcore/ptr.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index b82afecd7696c..07e8d253af857 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -24,8 +24,8 @@ //! to access only a single value, in which case the documentation omits the size //! and implicitly assumes it to be `size_of::()` bytes. //! -//! While we can't yet define whether an arbitrary pointer is valid, there -//! are a few rules regarding validity: +//! The precise rules for validity are not determined yet. The guarantees that are +//! provided at this point are very minimal: //! //! * A [null] pointer is *never* valid, not even for accesses of [size zero][zst]. //! * All pointers (except for the null pointer) are valid for all operations of @@ -35,9 +35,8 @@ //! access the same memory. //! //! These axioms, along with careful use of [`offset`] for pointer arithmentic, -//! are enough to correctly implement many useful things in unsafe code. Still, -//! unsafe code should be carefully examined since some of the finer -//! details—notably the [aliasing] rules—are not yet settled. For more +//! are enough to correctly implement many useful things in unsafe code. Stronger guarantees +//! will be provided eventually, as the [aliasing] rules are being determined. For more //! information, see the [book] as well as the section in the reference devoted //! to [undefined behavior][ub]. //! From fc63113f1fca416e88cafa10670f7743aaa82759 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Aug 2018 16:19:05 +0200 Subject: [PATCH 16/33] clarify ZST comment --- src/libcore/intrinsics.rs | 12 ++++++------ src/libcore/ptr.rs | 20 ++++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 9748feddddff7..c82eaa13eef6f 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -991,8 +991,8 @@ extern "rust-intrinsic" { /// in the region beginning at `*src` and the region beginning at `*dst` can /// [violate memory safety][read-ownership]. /// - /// These restrictions apply even if the effectively copied size (`count * - /// size_of::()`) is `0`. + /// Note that even if the effectively copied size (`count * size_of::()`) is + /// `0`, the pointers must be non-NULL and properly aligned. /// /// [`Copy`]: ../marker/trait.Copy.html /// [`read`]: ../ptr/fn.read.html @@ -1074,8 +1074,8 @@ extern "rust-intrinsic" { /// in the region beginning at `*src` and the region beginning at `*dst` can /// [violate memory safety][read-ownership]. /// - /// These restrictions apply even if the effectively copied size (`count * - /// size_of::()`) is `0`. + /// Note that even if the effectively copied size (`count * size_of::()`) is + /// `0`, the pointers must be non-NULL and properly aligned. /// /// [`Copy`]: ../marker/trait.Copy.html /// [`read`]: ../ptr/fn.read.html @@ -1121,8 +1121,8 @@ extern "rust-intrinsic" { /// value of `T`. Creating an invalid value of `T` can result in undefined /// behavior. /// - /// These restrictions apply even if the effectively written size (`count * - /// size_of::()`) is `0`. + /// Note that even if the effectively copied size (`count * size_of::()`) is + /// `0`, the pointer must be non-NULL and properly aligned. /// /// [valid]: ../ptr/index.html#safety /// diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 07e8d253af857..98f5ab21f2752 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -114,7 +114,7 @@ pub use intrinsics::write_bytes; /// again. [`write`] can be used to overwrite data without causing it to be /// dropped. /// -/// These restrictions apply even if `T` has size `0`. +/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. /// /// [valid]: ../ptr/index.html#safety /// [`Copy`]: ../marker/trait.Copy.html @@ -205,7 +205,7 @@ pub const fn null_mut() -> *mut T { 0 as *mut T } /// /// * Both `x` and `y` must be properly aligned. /// -/// These restrictions apply even if `T` has size `0`. +/// Note that even if `T` has size `0`, the pointers must be non-NULL and properly aligned. /// /// [valid]: ../ptr/index.html#safety /// @@ -274,7 +274,7 @@ pub unsafe fn swap(x: *mut T, y: *mut T) { /// size_of::()` bytes must *not* overlap with the region of memory /// beginning at `y` with the same size. /// -/// These restrictions apply even if `T` has size `0`. +/// Note that even if `T` has size `0`, the pointers must be non-NULL and properly aligned. /// /// [valid]: ../ptr/index.html#safety /// @@ -387,7 +387,7 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { /// /// * `dest` must be properly aligned. /// -/// These restrictions apply even if `T` has size `0`. +/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. /// /// [valid]: ../ptr/index.html#safety /// @@ -426,7 +426,7 @@ pub unsafe fn replace(dest: *mut T, mut src: T) -> T { /// * `src` must be properly aligned. Use [`read_unaligned`] if this is not the /// case. /// -/// These restrictions apply even if `T` has size `0`. +/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. /// /// ## Ownership of the Returned Value /// @@ -542,7 +542,7 @@ pub unsafe fn read(src: *const T) -> T { /// 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]. /// -/// These restrictions apply even if `T` has size `0`. +/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. /// /// [`Copy`]: ../marker/trait.Copy.html /// [`read`]: ./fn.read.html @@ -620,7 +620,7 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// * `dst` must be properly aligned. Use [`write_unaligned`] if this is not the /// case. /// -/// These restrictions apply even if `T` has size `0`. +/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. /// /// [valid]: ../ptr/index.html#safety /// [`write_unaligned`]: ./fn.write_unaligned.html @@ -693,7 +693,7 @@ pub unsafe fn write(dst: *mut T, src: T) { /// /// * `dst` must be [valid] for writes. /// -/// These restrictions apply even if `T` has size `0`. +/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. /// /// [valid]: ../ptr/index.html#safety /// @@ -778,7 +778,7 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// However, storing non-[`Copy`] types in volatile memory is almost certainly /// incorrect. /// -/// These restrictions apply even if `T` has size `0`. +/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. /// /// [valid]: ../ptr/index.html#safety /// [`Copy`]: ../marker/trait.Copy.html @@ -849,7 +849,7 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// /// * `dst` must be properly aligned. /// -/// These restrictions apply even if `T` has size `0`. +/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. /// /// [valid]: ../ptr/index.html#safety /// From 1ec66fb4b24a95e43908034363b9095ed0ea1afb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Aug 2018 16:26:48 +0200 Subject: [PATCH 17/33] apply comments --- src/libcore/intrinsics.rs | 16 ++++++++++------ src/libcore/ptr.rs | 25 +++++++++++++------------ 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index c82eaa13eef6f..bb4297e5493c9 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1024,10 +1024,9 @@ extern "rust-intrinsic" { /// // not alias, and two different vectors cannot own the same /// // memory. /// ptr::copy_nonoverlapping(src, dst, src_len); - /// } /// - /// unsafe { - /// // Truncate `src` without dropping its contents. + /// // Truncate `src` without dropping its contents. This cannot panic, + /// // so double-drops cannot happen. /// src.set_len(0); /// /// // Notify `dst` that it now holds the contents of `src`. @@ -1054,7 +1053,9 @@ extern "rust-intrinsic" { /// If the source and destination will *never* overlap, /// [`copy_nonoverlapping`] can be used instead. /// - /// `copy` is semantically equivalent to C's [`memmove`]. + /// `copy` is semantically equivalent to C's [`memmove`]. Copying takes place as + /// if the bytes were copied from `src` to a temporary array and then copied from + /// the array to `dst`- /// /// [`copy_nonoverlapping`]: ./fn.copy_nonoverlapping.html /// [`memmove`]: https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html#index-memmove @@ -1143,7 +1144,7 @@ extern "rust-intrinsic" { /// /// Creating an invalid value: /// - /// ```no_run + /// ``` /// use std::ptr; /// /// let mut v = Box::new(0i32); @@ -1155,7 +1156,10 @@ extern "rust-intrinsic" { /// } /// /// // At this point, using or dropping `v` results in undefined behavior. - /// // v = Box::new(0i32); // ERROR + /// // drop(v); // ERROR + /// + /// // Leaking it does not invoke drop and is fine: + /// mem::forget(v) /// ``` #[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 98f5ab21f2752..2b51e321cbdab 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -274,7 +274,8 @@ pub unsafe fn swap(x: *mut T, y: *mut T) { /// size_of::()` bytes must *not* overlap with the region of memory /// beginning at `y` with the same size. /// -/// Note that even if `T` has size `0`, the pointers must be non-NULL and properly aligned. +/// Note that even if the effectively copied size (`count * size_of::()`) is `0`, +/// the pointers must be non-NULL and properly aligned. /// /// [valid]: ../ptr/index.html#safety /// @@ -369,7 +370,7 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { } } -/// Moves `src` into the pointed `dest`, returning the previous `dest` value. +/// Moves `src` into the pointed `dst`, returning the previous `dst` value. /// /// Neither value is dropped. /// @@ -383,9 +384,9 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * `dest` must be [valid] for writes. +/// * `dst` must be [valid] for writes. /// -/// * `dest` must be properly aligned. +/// * `dst` must be properly aligned. /// /// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. /// @@ -409,8 +410,8 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] -pub unsafe fn replace(dest: *mut T, mut src: T) -> T { - mem::swap(&mut *dest, &mut src); // cannot overlap +pub unsafe fn replace(dst: *mut T, mut src: T) -> T { + mem::swap(&mut *dst, &mut src); // cannot overlap src } @@ -447,8 +448,8 @@ pub unsafe fn replace(dest: *mut T, mut src: T) -> T { /// /// let mut s = String::from("foo"); /// unsafe { -/// // `s2` now points to the same underlying memory as `s1`. -/// let mut s2 = ptr::read(&s); +/// // `s2` now points to the same underlying memory as `s`. +/// let mut s2: String = ptr::read(&s); /// /// assert_eq!(s2, "foo"); /// @@ -558,7 +559,6 @@ pub unsafe fn read(src: *const T) -> T { /// use std::ptr; /// /// #[repr(packed, C)] -/// #[derive(Default)] /// struct Packed { /// _padding: u8, /// unaligned: u32, @@ -570,10 +570,11 @@ pub unsafe fn read(src: *const T) -> T { /// }; /// /// let v = unsafe { -/// // Take a reference to a 32-bit integer which is not aligned. -/// let unaligned = &x.unaligned; +/// // Take the address of a 32-bit integer which is not aligned. +/// // This must be done as a raw pointer; unaligned references are invalid. +/// let unaligned = &x.unaligned as *const u32; /// -/// // Dereferencing normally will emit an unaligned load instruction, +/// // Dereferencing normally will emit an aligned load instruction, /// // causing undefined behavior. /// // let v = *unaligned; // ERROR /// From e869b81b93c43e9ef72f9ae220629f28f8e6f7cf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Aug 2018 17:07:24 +0200 Subject: [PATCH 18/33] address remaining remarks and add example for dropping unaligned data --- src/libcore/intrinsics.rs | 6 +++--- src/libcore/ptr.rs | 36 ++++++++++++++++++++++++++++++++---- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index bb4297e5493c9..bb599a6707823 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1117,10 +1117,10 @@ extern "rust-intrinsic" { /// /// * `dst` must be properly aligned. /// - /// Additionally, the caller must ensure that writing `count * + /// Additionally, the caller should 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. + /// value of `T`. Using a region of memory typed as a `T` that contains an + /// invalid value of `T` is undefined behavior. /// /// Note that even if the effectively copied size (`count * size_of::()`) is /// `0`, the pointer must be non-NULL and properly aligned. diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 2b51e321cbdab..cc42355643e3d 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -106,7 +106,9 @@ pub use intrinsics::write_bytes; /// /// * `to_drop` must be [valid] for reads. /// -/// * `to_drop` must be properly aligned. +/// * `to_drop` must be properly aligned. See the example below for how to drop +/// an unaligned pointer. + /// /// Additionally, if `T` is not [`Copy`], using the pointed-to value after /// calling `drop_in_place` can cause undefined behavior. Note that `*to_drop = @@ -137,6 +139,7 @@ pub use intrinsics::write_bytes; /// // 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]); +/// // Shorten `v` to prevent the last item from being dropped. /// v.set_len(1); /// } /// @@ -145,6 +148,31 @@ pub use intrinsics::write_bytes; /// // Ensure that the last item was dropped. /// assert!(weak.upgrade().is_none()); /// ``` +/// +/// Drops a potentially unaligned value by copying it to aligned memory first: +/// ``` +/// use std::ptr; +/// use std::mem; +/// +/// unsafe fn drop_after_copy(to_drop: *mut T) { +/// let mut copy: T = mem::uninitialized(); +/// let copy = &mut copy as *mut T; +/// ptr::copy(to_drop, copy, 1); +/// ptr::drop_in_place(copy); +/// } +/// +/// #[repr(packed, C)] +/// struct Packed { +/// _padding: u8, +/// unaligned: Vec, +/// } +/// +/// let mut p = Packed { _padding: 0, unaligned: vec![42] }; +/// unsafe { +/// drop_after_copy(&mut p.unaligned as *mut _); +/// mem::forget(p); +/// } +/// ``` #[stable(feature = "drop_in_place", since = "1.8.0")] #[lang = "drop_in_place"] #[allow(unconditional_recursion)] @@ -601,7 +629,7 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// dropping the old value. /// /// `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 +/// allocations or resources, so care should be taken not to overwrite an object /// that should be dropped. /// /// Additionally, it does not drop `src`. Semantically, `src` is moved into the @@ -676,7 +704,7 @@ pub unsafe fn write(dst: *mut T, src: T) { /// Unlike [`write`], the pointer may be unaligned. /// /// `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 +/// could leak allocations or resources, so care should be taken not to overwrite /// an object that should be dropped. /// /// Additionally, it does not drop `src`. Semantically, `src` is moved into the @@ -820,7 +848,7 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// [`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 +/// could leak allocations or resources, so care should be taken not to overwrite /// an object that should be dropped. /// /// Additionally, it does not drop `src`. Semantically, `src` is moved into the From d97f61f10ebfaa57f5010301ebfb60e0701e904f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Aug 2018 17:27:55 +0200 Subject: [PATCH 19/33] avoid shadowing; fix examples --- src/libcore/intrinsics.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index bb599a6707823..61d4390ebb782 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1017,13 +1017,13 @@ extern "rust-intrinsic" { /// unsafe { /// // 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(); + /// let dst_ptr = dst.as_mut_ptr().offset(dst_len as isize); + /// let src_ptr = 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); + /// ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_len); /// /// // Truncate `src` without dropping its contents. This cannot panic, /// // so double-drops cannot happen. @@ -1145,7 +1145,7 @@ extern "rust-intrinsic" { /// Creating an invalid value: /// /// ``` - /// use std::ptr; + /// use std::{mem, ptr}; /// /// let mut v = Box::new(0i32); /// From c06f5517dc00798c85ecad37504ebd0b29ede35a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Aug 2018 17:37:58 +0200 Subject: [PATCH 20/33] improve volatile comments --- src/libcore/ptr.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index cc42355643e3d..6e664faa73065 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -774,8 +774,8 @@ 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`]. +/// Memory accessed with `read_volatile` or [`write_volatile`] should not be +/// accessed with non-volatile operations. /// /// [`write_volatile`]: ./fn.write_volatile.html /// @@ -844,8 +844,8 @@ 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`]. +/// Memory accessed with [`read_volatile`] or `write_volatile` should not be +/// accessed with non-volatile operations. /// /// `write_volatile` does not drop the contents of `dst`. This is safe, but it /// could leak allocations or resources, so care should be taken not to overwrite From 274122426e5004c8bc6fb37fe55511812671a45a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Aug 2018 17:48:34 +0200 Subject: [PATCH 21/33] fix example --- src/libcore/ptr.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 6e664faa73065..b811b93929532 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -149,7 +149,8 @@ pub use intrinsics::write_bytes; /// assert!(weak.upgrade().is_none()); /// ``` /// -/// Drops a potentially unaligned value by copying it to aligned memory first: +/// Unaligned values cannot be dropped in place, they must be copied to an aligned +/// location first: /// ``` /// use std::ptr; /// use std::mem; @@ -158,7 +159,7 @@ pub use intrinsics::write_bytes; /// let mut copy: T = mem::uninitialized(); /// let copy = &mut copy as *mut T; /// ptr::copy(to_drop, copy, 1); -/// ptr::drop_in_place(copy); +/// drop(copy); /// } /// /// #[repr(packed, C)] From 18a7bdb568b222b20e1bf30f23f945a10ea60c78 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Aug 2018 18:05:49 +0200 Subject: [PATCH 22/33] fix example --- src/libcore/ptr.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index b811b93929532..9d9b6e4e6f8ca 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -157,8 +157,7 @@ pub use intrinsics::write_bytes; /// /// unsafe fn drop_after_copy(to_drop: *mut T) { /// let mut copy: T = mem::uninitialized(); -/// let copy = &mut copy as *mut T; -/// ptr::copy(to_drop, copy, 1); +/// ptr::copy(to_drop, &mut copy, 1); /// drop(copy); /// } /// From 4ed469c4831f00ea9afec5e7becd56be018df45e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 31 Aug 2018 09:54:37 +0200 Subject: [PATCH 23/33] turn ptr type method docs into links to docs of free functions, to avoid duplication and inconsistency --- src/libcore/ptr.rs | 477 +++++---------------------------------------- 1 file changed, 44 insertions(+), 433 deletions(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 9d9b6e4e6f8ca..f112a96ea15f5 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -1401,29 +1401,9 @@ impl *const T { /// Reads the value from `self` without moving it. This leaves the /// memory in `self` unchanged. /// - /// # Safety - /// - /// Beyond accepting a raw pointer, this is unsafe because it semantically - /// moves the value out of `self` without preventing further usage of `self`. - /// If `T` is not `Copy`, then care must be taken to ensure that the value at - /// `self` is not used before the data is overwritten again (e.g. with `write`, - /// `write_bytes`, or `copy`). Note that `*self = foo` counts as a use - /// because it will attempt to drop the value previously at `*self`. - /// - /// The pointer must be aligned; use `read_unaligned` if that is not the case. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let x = 12; - /// let y = &x as *const i32; + /// See [`ptr::read`] for safety concerns and examples. /// - /// unsafe { - /// assert_eq!(y.read(), 12); - /// } - /// ``` + /// [`ptr::read`]: ./ptr/fn.read.html #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn read(self) -> T @@ -1439,47 +1419,9 @@ impl *const T { /// to not be elided or reordered by the compiler across other volatile /// operations. /// - /// # Notes - /// - /// Rust does not currently have a rigorously and formally defined memory model, - /// so the precise semantics of what "volatile" means here is subject to change - /// over time. That being said, the semantics will almost always end up pretty - /// similar to [C11's definition of volatile][c11]. - /// - /// The compiler shouldn't change the relative order or number of volatile - /// memory operations. However, volatile memory operations on zero-sized types - /// (e.g. if a zero-sized type is passed to `read_volatile`) are no-ops - /// and may be ignored. - /// - /// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf - /// - /// # Safety - /// - /// Beyond accepting a raw pointer, this is unsafe because it semantically - /// moves the value out of `self` without preventing further usage of `self`. - /// If `T` is not `Copy`, then care must be taken to ensure that the value at - /// `self` is not used before the data is overwritten again (e.g. with `write`, - /// `write_bytes`, or `copy`). Note that `*self = foo` counts as a use - /// because it will attempt to drop the value previously at `*self`. - /// - /// Just like in C, whether an operation is volatile has no bearing whatsoever - /// on questions involving concurrent access from multiple threads. Volatile - /// accesses behave exactly like non-atomic accesses in that regard. In particular, - /// a race between a `read_volatile` and any write operation to the same location - /// is undefined behavior. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let x = 12; - /// let y = &x as *const i32; + /// See [`ptr::read_volatile`] for safety concerns and examples. /// - /// unsafe { - /// assert_eq!(y.read_volatile(), 12); - /// } - /// ``` + /// [`ptr::read_volatile`]: ./ptr/fn.read_volatile.html #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn read_volatile(self) -> T @@ -1493,27 +1435,9 @@ impl *const T { /// /// Unlike `read`, the pointer may be unaligned. /// - /// # Safety - /// - /// Beyond accepting a raw pointer, this is unsafe because it semantically - /// moves the value out of `self` without preventing further usage of `self`. - /// If `T` is not `Copy`, then care must be taken to ensure that the value at - /// `self` is not used before the data is overwritten again (e.g. with `write`, - /// `write_bytes`, or `copy`). Note that `*self = foo` counts as a use - /// because it will attempt to drop the value previously at `*self`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let x = 12; - /// let y = &x as *const i32; + /// See [`ptr::read_unaligned`] for safety concerns and examples. /// - /// unsafe { - /// assert_eq!(y.read_unaligned(), 12); - /// } - /// ``` + /// [`ptr::read_unaligned`]: ./ptr/fn.read_unaligned.html #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn read_unaligned(self) -> T @@ -1525,30 +1449,11 @@ impl *const T { /// Copies `count * size_of` bytes from `self` to `dest`. The source /// and destination may overlap. /// - /// NOTE: this has the *same* argument order as `ptr::copy`. - /// - /// This is semantically equivalent to C's `memmove`. - /// - /// # Safety - /// - /// Care must be taken with the ownership of `self` and `dest`. - /// This method semantically moves the values of `self` into `dest`. - /// However it does not drop the contents of `dest`, or prevent the contents - /// of `self` from being dropped or used. - /// - /// # Examples + /// NOTE: this has the *same* argument order as [`ptr::copy`]. /// - /// Efficiently create a Rust vector from an unsafe buffer: + /// See [`ptr::copy`] for safety concerns and examples. /// - /// ``` - /// # #[allow(dead_code)] - /// unsafe fn from_buf_raw(ptr: *const T, elts: usize) -> Vec { - /// let mut dst = Vec::with_capacity(elts); - /// dst.set_len(elts); - /// ptr.copy_to(dst.as_mut_ptr(), elts); - /// dst - /// } - /// ``` + /// [`ptr::copy`]: ./ptr/fn.copy.html #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn copy_to(self, dest: *mut T, count: usize) @@ -1560,32 +1465,11 @@ impl *const T { /// Copies `count * size_of` bytes from `self` to `dest`. The source /// and destination may *not* overlap. /// - /// NOTE: this has the *same* argument order as `ptr::copy_nonoverlapping`. + /// NOTE: this has the *same* argument order as [`ptr::copy_nonoverlapping`]. /// - /// `copy_nonoverlapping` is semantically equivalent to C's `memcpy`. + /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. /// - /// # 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 `self` and - /// `self`. This method semantically moves the values of `self` into `dest`. - /// However it does not drop the contents of `dest`, or prevent the contents - /// of `self` from being dropped or used. - /// - /// # Examples - /// - /// Efficiently create a Rust vector from an unsafe buffer: - /// - /// ``` - /// # #[allow(dead_code)] - /// unsafe fn from_buf_raw(ptr: *const T, elts: usize) -> Vec { - /// let mut dst = Vec::with_capacity(elts); - /// dst.set_len(elts); - /// ptr.copy_to_nonoverlapping(dst.as_mut_ptr(), elts); - /// dst - /// } - /// ``` + /// [`ptr::copy_nonoverlapping`]: ./ptr/fn.copy_nonoverlapping.html #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize) @@ -2155,29 +2039,9 @@ impl *mut T { /// Reads the value from `self` without moving it. This leaves the /// memory in `self` unchanged. /// - /// # Safety - /// - /// Beyond accepting a raw pointer, this is unsafe because it semantically - /// moves the value out of `self` without preventing further usage of `self`. - /// If `T` is not `Copy`, then care must be taken to ensure that the value at - /// `self` is not used before the data is overwritten again (e.g. with `write`, - /// `write_bytes`, or `copy`). Note that `*self = foo` counts as a use - /// because it will attempt to drop the value previously at `*self`. - /// - /// The pointer must be aligned; use `read_unaligned` if that is not the case. + /// See [`ptr::read`] for safety concerns and examples. /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let x = 12; - /// let y = &x as *const i32; - /// - /// unsafe { - /// assert_eq!(y.read(), 12); - /// } - /// ``` + /// [`ptr::read`]: ./ptr/fn.read.html #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn read(self) -> T @@ -2193,47 +2057,9 @@ impl *mut T { /// to not be elided or reordered by the compiler across other volatile /// operations. /// - /// # Notes - /// - /// Rust does not currently have a rigorously and formally defined memory model, - /// so the precise semantics of what "volatile" means here is subject to change - /// over time. That being said, the semantics will almost always end up pretty - /// similar to [C11's definition of volatile][c11]. - /// - /// The compiler shouldn't change the relative order or number of volatile - /// memory operations. However, volatile memory operations on zero-sized types - /// (e.g. if a zero-sized type is passed to `read_volatile`) are no-ops - /// and may be ignored. - /// - /// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf + /// See [`ptr::read_volatile`] for safety concerns and examples. /// - /// # Safety - /// - /// Beyond accepting a raw pointer, this is unsafe because it semantically - /// moves the value out of `self` without preventing further usage of `self`. - /// If `T` is not `Copy`, then care must be taken to ensure that the value at - /// `self` is not used before the data is overwritten again (e.g. with `write`, - /// `write_bytes`, or `copy`). Note that `*self = foo` counts as a use - /// because it will attempt to drop the value previously at `*self`. - /// - /// Just like in C, whether an operation is volatile has no bearing whatsoever - /// on questions involving concurrent access from multiple threads. Volatile - /// accesses behave exactly like non-atomic accesses in that regard. In particular, - /// a race between a `read_volatile` and any write operation to the same location - /// is undefined behavior. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let x = 12; - /// let y = &x as *const i32; - /// - /// unsafe { - /// assert_eq!(y.read_volatile(), 12); - /// } - /// ``` + /// [`ptr::read_volatile`]: ./ptr/fn.read_volatile.html #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn read_volatile(self) -> T @@ -2247,27 +2073,9 @@ impl *mut T { /// /// Unlike `read`, the pointer may be unaligned. /// - /// # Safety - /// - /// Beyond accepting a raw pointer, this is unsafe because it semantically - /// moves the value out of `self` without preventing further usage of `self`. - /// If `T` is not `Copy`, then care must be taken to ensure that the value at - /// `self` is not used before the data is overwritten again (e.g. with `write`, - /// `write_bytes`, or `copy`). Note that `*self = foo` counts as a use - /// because it will attempt to drop the value previously at `*self`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let x = 12; - /// let y = &x as *const i32; + /// See [`ptr::read_unaligned`] for safety concerns and examples. /// - /// unsafe { - /// assert_eq!(y.read_unaligned(), 12); - /// } - /// ``` + /// [`ptr::read_unaligned`]: ./ptr/fn.read_unaligned.html #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn read_unaligned(self) -> T @@ -2279,30 +2087,11 @@ impl *mut T { /// Copies `count * size_of` bytes from `self` to `dest`. The source /// and destination may overlap. /// - /// NOTE: this has the *same* argument order as `ptr::copy`. + /// NOTE: this has the *same* argument order as [`ptr::copy`]. /// - /// This is semantically equivalent to C's `memmove`. + /// See [`ptr::copy`] for safety concerns and examples. /// - /// # Safety - /// - /// Care must be taken with the ownership of `self` and `dest`. - /// This method semantically moves the values of `self` into `dest`. - /// However it does not drop the contents of `self`, or prevent the contents - /// of `dest` from being dropped or used. - /// - /// # Examples - /// - /// Efficiently create a Rust vector from an unsafe buffer: - /// - /// ``` - /// # #[allow(dead_code)] - /// unsafe fn from_buf_raw(ptr: *const T, elts: usize) -> Vec { - /// let mut dst = Vec::with_capacity(elts); - /// dst.set_len(elts); - /// ptr.copy_to(dst.as_mut_ptr(), elts); - /// dst - /// } - /// ``` + /// [`ptr::copy`]: ./ptr/fn.copy.html #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn copy_to(self, dest: *mut T, count: usize) @@ -2314,32 +2103,11 @@ impl *mut T { /// Copies `count * size_of` bytes from `self` to `dest`. The source /// and destination may *not* overlap. /// - /// NOTE: this has the *same* argument order as `ptr::copy_nonoverlapping`. - /// - /// `copy_nonoverlapping` is semantically equivalent to C's `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 `self` and - /// `self`. This method semantically moves the values of `self` into `dest`. - /// However it does not drop the contents of `dest`, or prevent the contents - /// of `self` from being dropped or used. - /// - /// # Examples + /// NOTE: this has the *same* argument order as [`ptr::copy_nonoverlapping`]. /// - /// Efficiently create a Rust vector from an unsafe buffer: + /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. /// - /// ``` - /// # #[allow(dead_code)] - /// unsafe fn from_buf_raw(ptr: *const T, elts: usize) -> Vec { - /// let mut dst = Vec::with_capacity(elts); - /// dst.set_len(elts); - /// ptr.copy_to_nonoverlapping(dst.as_mut_ptr(), elts); - /// dst - /// } - /// ``` + /// [`ptr::copy_nonoverlapping`]: ./ptr/fn.copy_nonoverlapping.html #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize) @@ -2351,30 +2119,11 @@ impl *mut T { /// Copies `count * size_of` bytes from `src` to `self`. The source /// and destination may overlap. /// - /// NOTE: this has the *opposite* argument order of `ptr::copy`. - /// - /// This is semantically equivalent to C's `memmove`. - /// - /// # Safety - /// - /// Care must be taken with the ownership of `src` and `self`. - /// This method semantically moves the values of `src` into `self`. - /// However it does not drop the contents of `self`, or prevent the contents - /// of `src` from being dropped or used. - /// - /// # Examples + /// NOTE: this has the *opposite* argument order of [`ptr::copy`]. /// - /// Efficiently create a Rust vector from an unsafe buffer: + /// See [`ptr::copy`] for safety concerns and examples. /// - /// ``` - /// # #[allow(dead_code)] - /// unsafe fn from_buf_raw(ptr: *const T, elts: usize) -> Vec { - /// let mut dst: Vec = Vec::with_capacity(elts); - /// dst.set_len(elts); - /// dst.as_mut_ptr().copy_from(ptr, elts); - /// dst - /// } - /// ``` + /// [`ptr::copy`]: ./ptr/fn.copy.html #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn copy_from(self, src: *const T, count: usize) @@ -2386,32 +2135,11 @@ impl *mut T { /// Copies `count * size_of` bytes from `src` to `self`. The source /// and destination may *not* overlap. /// - /// NOTE: this has the *opposite* argument order of `ptr::copy_nonoverlapping`. - /// - /// `copy_nonoverlapping` is semantically equivalent to C's `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 - /// `self`. This method semantically moves the values of `src` into `self`. - /// However it does not drop the contents of `self`, or prevent the contents - /// of `src` from being dropped or used. - /// - /// # Examples + /// NOTE: this has the *opposite* argument order of [`ptr::copy_nonoverlapping`]. /// - /// Efficiently create a Rust vector from an unsafe buffer: + /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. /// - /// ``` - /// # #[allow(dead_code)] - /// unsafe fn from_buf_raw(ptr: *const T, elts: usize) -> Vec { - /// let mut dst: Vec = Vec::with_capacity(elts); - /// dst.set_len(elts); - /// dst.as_mut_ptr().copy_from_nonoverlapping(ptr, elts); - /// dst - /// } - /// ``` + /// [`ptr::copy_nonoverlapping`]: ./ptr/fn.copy_nonoverlapping.html #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn copy_from_nonoverlapping(self, src: *const T, count: usize) @@ -2422,21 +2150,9 @@ impl *mut T { /// Executes the destructor (if any) of the pointed-to value. /// - /// This has two use cases: + /// See [`ptr::drop_in_place`] for safety concerns and examples. /// - /// * 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 - /// 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. - /// - /// # Safety - /// - /// This has all the same safety problems as `ptr::read` with respect to - /// invalid pointers, types, and double drops. + /// [`ptr::drop_in_place`]: ./ptr/fn.drop_in_place.html #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn drop_in_place(self) { @@ -2446,36 +2162,9 @@ impl *mut T { /// Overwrites a memory location with the given value without reading or /// dropping the old value. /// - /// # Safety - /// - /// This operation is marked unsafe because it writes through a raw pointer. - /// - /// It does not drop the contents of `self`. 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 `val`. Semantically, `val` is moved into the - /// location pointed to by `self`. - /// - /// This is appropriate for initializing uninitialized memory, or overwriting - /// memory that has previously been `read` from. - /// - /// The pointer must be aligned; use `write_unaligned` if that is not the case. - /// - /// # Examples + /// See [`ptr::write`] for safety concerns and examples. /// - /// Basic usage: - /// - /// ``` - /// let mut x = 0; - /// let y = &mut x as *mut i32; - /// let z = 12; - /// - /// unsafe { - /// y.write(z); - /// assert_eq!(y.read(), 12); - /// } - /// ``` + /// [`ptr::write`]: ./ptr/fn.write.html #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn write(self, val: T) @@ -2487,16 +2176,9 @@ impl *mut T { /// Invokes memset on the specified pointer, setting `count * size_of::()` /// bytes of memory starting at `self` to `val`. /// - /// # Examples + /// See [`ptr::write_bytes`] for safety concerns and examples. /// - /// ``` - /// let mut vec = vec![0; 4]; - /// unsafe { - /// let vec_ptr = vec.as_mut_ptr(); - /// vec_ptr.write_bytes(b'a', 2); - /// } - /// assert_eq!(vec, [b'a', b'a', 0, 0]); - /// ``` + /// [`ptr::write_bytes`]: ./ptr/fn.write_bytes.html #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn write_bytes(self, val: u8, count: usize) @@ -2512,51 +2194,9 @@ impl *mut T { /// to not be elided or reordered by the compiler across other volatile /// operations. /// - /// # Notes + /// See [`ptr::write_volatile`] for safety concerns and examples. /// - /// Rust does not currently have a rigorously and formally defined memory model, - /// so the precise semantics of what "volatile" means here is subject to change - /// over time. That being said, the semantics will almost always end up pretty - /// similar to [C11's definition of volatile][c11]. - /// - /// The compiler shouldn't change the relative order or number of volatile - /// memory operations. However, volatile memory operations on zero-sized types - /// (e.g. if a zero-sized type is passed to `write_volatile`) are no-ops - /// and may be ignored. - /// - /// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf - /// - /// # Safety - /// - /// This operation is marked unsafe because it accepts a raw pointer. - /// - /// It does not drop the contents of `self`. This is safe, but it could leak - /// allocations or resources, so care must be taken not to overwrite an object - /// that should be dropped. - /// - /// This is appropriate for initializing uninitialized memory, or overwriting - /// memory that has previously been `read` from. - /// - /// Just like in C, whether an operation is volatile has no bearing whatsoever - /// on questions involving concurrent access from multiple threads. Volatile - /// accesses behave exactly like non-atomic accesses in that regard. In particular, - /// a race between a `write_volatile` and any other operation (reading or writing) - /// on the same location is undefined behavior. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let mut x = 0; - /// let y = &mut x as *mut i32; - /// let z = 12; - /// - /// unsafe { - /// y.write_volatile(z); - /// assert_eq!(y.read_volatile(), 12); - /// } - /// ``` + /// [`ptr::write_volatile`]: ./ptr/fn.write_volatile.html #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn write_volatile(self, val: T) @@ -2570,34 +2210,9 @@ impl *mut T { /// /// Unlike `write`, the pointer may be unaligned. /// - /// # Safety - /// - /// This operation is marked unsafe because it writes through a raw pointer. - /// - /// It does not drop the contents of `self`. This is safe, but it could leak - /// allocations or resources, so care must be taken not to overwrite an object - /// that should be dropped. + /// See [`ptr::write_unaligned`] for safety concerns and examples. /// - /// Additionally, it does not drop `self`. Semantically, `self` is moved into the - /// location pointed to by `val`. - /// - /// This is appropriate for initializing uninitialized memory, or overwriting - /// memory that has previously been `read` from. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let mut x = 0; - /// let y = &mut x as *mut i32; - /// let z = 12; - /// - /// unsafe { - /// y.write_unaligned(z); - /// assert_eq!(y.read_unaligned(), 12); - /// } - /// ``` + /// [`ptr::write_unaligned`]: ./ptr/fn.write_unaligned.html #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn write_unaligned(self, val: T) @@ -2609,10 +2224,9 @@ impl *mut T { /// Replaces the value at `self` with `src`, returning the old /// value, without dropping either. /// - /// # Safety + /// See [`ptr::replace`] for safety concerns and examples. /// - /// This is only unsafe because it accepts a raw pointer. - /// Otherwise, this operation is identical to `mem::replace`. + /// [`ptr::replace`]: ./ptr/fn.replace.html #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn replace(self, src: T) -> T @@ -2625,12 +2239,9 @@ impl *mut T { /// deinitializing either. They may overlap, unlike `mem::swap` which is /// otherwise equivalent. /// - /// # Safety - /// - /// This function copies the memory through the raw pointers passed to it - /// as arguments. + /// See [`ptr::swap`] for safety concerns and examples. /// - /// Ensure that these pointers are valid before calling `swap`. + /// [`ptr::swap`]: ./ptr/fn.swap.html #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn swap(self, with: *mut T) From dc2237c49fea94c8308f989c43f042a0cc327419 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 31 Aug 2018 17:01:53 +0200 Subject: [PATCH 24/33] apply feedback --- src/libcore/intrinsics.rs | 33 ++++++++++++++++++++------------- src/libcore/ptr.rs | 15 ++++++++------- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 61d4390ebb782..927c6f26b62a7 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -967,10 +967,11 @@ extern "rust-intrinsic" { /// /// For regions of memory which might overlap, use [`copy`] instead. /// - /// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`]. + /// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but + /// with the argument order swapped. /// /// [`copy`]: ./fn.copy.html - /// [`memcpy`]: https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html#index-memcpy + /// [`memcpy`]: https://en.cppreference.com/w/c/string/byte/memcpy /// /// # Safety /// @@ -1020,15 +1021,15 @@ extern "rust-intrinsic" { /// let dst_ptr = dst.as_mut_ptr().offset(dst_len as isize); /// let src_ptr = src.as_ptr(); /// + /// // Truncate `src` without dropping its contents. We do this first, + /// // to avoid problems in case something further down panics. + /// src.set_len(0); + /// /// // The two regions cannot overlap becuase mutable references do /// // not alias, and two different vectors cannot own the same /// // memory. /// ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_len); /// - /// // Truncate `src` without dropping its contents. This cannot panic, - /// // so double-drops cannot happen. - /// src.set_len(0); - /// /// // Notify `dst` that it now holds the contents of `src`. /// dst.set_len(dst_len + src_len); /// } @@ -1053,12 +1054,12 @@ extern "rust-intrinsic" { /// If the source and destination will *never* overlap, /// [`copy_nonoverlapping`] can be used instead. /// - /// `copy` is semantically equivalent to C's [`memmove`]. Copying takes place as - /// if the bytes were copied from `src` to a temporary array and then copied from - /// the array to `dst`- + /// `copy` is semantically equivalent to C's [`memmove`], but with the argument + /// order swapped. Copying takes place as if the bytes were copied from `src` + /// to a temporary array and then copied from the array to `dst`. /// /// [`copy_nonoverlapping`]: ./fn.copy_nonoverlapping.html - /// [`memmove`]: https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html#index-memmove + /// [`memmove`]: https://en.cppreference.com/w/c/string/byte/memmove /// /// # Safety /// @@ -1107,7 +1108,7 @@ extern "rust-intrinsic" { /// `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 + /// [`memset`]: https://en.cppreference.com/w/c/string/byte/memset /// /// # Safety /// @@ -1158,8 +1159,14 @@ extern "rust-intrinsic" { /// // At this point, using or dropping `v` results in undefined behavior. /// // drop(v); // ERROR /// - /// // Leaking it does not invoke drop and is fine: - /// mem::forget(v) + /// // Even leaking `v` "uses" it, and henc eis undefined behavior. + /// // mem::forget(v); // ERROR + /// + /// // Let us instead put in a valid value + /// ptr::write(&mut v, Box::new(42i32); + /// + /// // Now the box is fine + /// assert_eq!(*v, 42); /// ``` #[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 f112a96ea15f5..a6c3e544e165b 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME: talk about offset, copy_memory, copy_nonoverlapping_memory - //! Manually manage memory through raw pointers. //! //! *[See also the pointer primitive types](../../std/primitive.pointer.html).* @@ -42,8 +40,10 @@ //! //! ## Alignment //! -//! Valid pointers are not necessarily properly aligned. However, most functions -//! require their arguments to be properly aligned, and will explicitly state +//! Valid pointers as defined above are not necessarily properly aligned (where +//! "proper" alignment is defind by the pointee type, i.e., `*const T` must be +//! aligned to `mem::align_of::()`). However, most functions require their +//! arguments to be properly aligned, and will explicitly state //! this requirement in their documentation. Notable exceptions to this are //! [`read_unaligned`] and [`write_unaligned`]. //! @@ -136,11 +136,12 @@ pub use intrinsics::write_bytes; /// let mut v = vec![Rc::new(0), last]; /// /// unsafe { +/// // Shorten `v` to prevent the last item from being dropped. We do that first, +/// // to prevent issues if the `drop_in_place` below panics. +/// v.set_len(1); /// // 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]); -/// // Shorten `v` to prevent the last item from being dropped. -/// v.set_len(1); /// } /// /// assert_eq!(v, &[0.into()]); @@ -745,7 +746,7 @@ pub unsafe fn write(dst: *mut T, src: T) { /// /// unsafe { /// // Take a reference to a 32-bit integer which is not aligned. -/// let unaligned = &mut x.unaligned; +/// let unaligned = &mut x.unaligned as *mut u32; /// /// // Dereferencing normally will emit an unaligned store instruction, /// // causing undefined behavior. From b463871df555984fddf1d4cb59d12119a28e98df Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 31 Aug 2018 17:02:39 +0200 Subject: [PATCH 25/33] (un)aligned --- src/libcore/ptr.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index a6c3e544e165b..adf107dca2231 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -748,8 +748,8 @@ pub unsafe fn write(dst: *mut T, src: T) { /// // Take a reference to a 32-bit integer which is not aligned. /// let unaligned = &mut x.unaligned as *mut u32; /// -/// // Dereferencing normally will emit an unaligned store instruction, -/// // causing undefined behavior. +/// // Dereferencing normally will emit an aligned store instruction, +/// // causing undefined behavior because the pointer is not aligned. /// // *unaligned = v; // ERROR /// /// // Instead, use `write_unaligned` to write improperly aligned values. From 408a6a00c228bbc762aa34f96a003703019c9e8d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 31 Aug 2018 18:25:42 +0200 Subject: [PATCH 26/33] fix doctests --- src/libcore/intrinsics.rs | 8 +++++--- src/libcore/ptr.rs | 4 +++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 927c6f26b62a7..659b7a23ed922 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1146,7 +1146,7 @@ extern "rust-intrinsic" { /// Creating an invalid value: /// /// ``` - /// use std::{mem, ptr}; + /// use std::ptr; /// /// let mut v = Box::new(0i32); /// @@ -1162,8 +1162,10 @@ extern "rust-intrinsic" { /// // Even leaking `v` "uses" it, and henc eis undefined behavior. /// // mem::forget(v); // ERROR /// - /// // Let us instead put in a valid value - /// ptr::write(&mut v, Box::new(42i32); + /// unsafe { + /// // Let us instead put in a valid value + /// ptr::write(&mut v, Box::new(42i32)); + /// } /// /// // Now the box is fine /// assert_eq!(*v, 42); diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index adf107dca2231..dba8513d5f099 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -136,12 +136,14 @@ pub use intrinsics::write_bytes; /// let mut v = vec![Rc::new(0), last]; /// /// unsafe { +/// // Get a raw pointer to the last element in `v`. +/// let ptr = &mut v[1] as *mut _; /// // Shorten `v` to prevent the last item from being dropped. We do that first, /// // to prevent issues if the `drop_in_place` below panics. /// v.set_len(1); /// // 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]); +/// ptr::drop_in_place(ptr); /// } /// /// assert_eq!(v, &[0.into()]); From 755de3c6848a5abf9e20ee9e866e04a1e711d8b8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 1 Sep 2018 17:50:54 +0200 Subject: [PATCH 27/33] Valid raw pointers --- 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 dba8513d5f099..3f117ff612ed3 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -40,7 +40,7 @@ //! //! ## Alignment //! -//! Valid pointers as defined above are not necessarily properly aligned (where +//! Valid raw pointers as defined above are not necessarily properly aligned (where //! "proper" alignment is defind by the pointee type, i.e., `*const T` must be //! aligned to `mem::align_of::()`). However, most functions require their //! arguments to be properly aligned, and will explicitly state From bc809e01eece1ec55adc781d25e54feac903157a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 1 Sep 2018 18:00:10 +0200 Subject: [PATCH 28/33] remark on concurrency in validity section --- src/libcore/ptr.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 3f117ff612ed3..5c16c8acae596 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -28,6 +28,12 @@ //! * A [null] pointer is *never* valid, not even for accesses of [size zero][zst]. //! * All pointers (except for the null pointer) are valid for all operations of //! [size zero][zst]. +//! * All accesses performed by functions in this module are *non-atomic* in the sense +//! of [atomic operations] used to synchronize between threads. This means it is +//! undefined behavior to perform two concurrent accesses to the same location from different +//! threads unless both accesses only read from memory. Notice that this explicitly +//! includes [`read_volatile`] and [`write_volatile`]: Volatile accesses cannot +//! be used for inter-thread synchronization. //! * The result of casting a reference to a pointer is valid for as long as the //! underlying object is live and no reference (just raw pointers) is used to //! access the same memory. @@ -56,10 +62,13 @@ //! [ub]: ../../reference/behavior-considered-undefined.html //! [null]: ./fn.null.html //! [zst]: ../../nomicon/exotic-sizes.html#zero-sized-types-zsts +//! [atomic operations]: ../../std/sync/atomic/index.html //! [`copy`]: ../../std/ptr/fn.copy.html //! [`offset`]: ../../std/primitive.pointer.html#method.offset //! [`read_unaligned`]: ./fn.read_unaligned.html //! [`write_unaligned`]: ./fn.write_unaligned.html +//! [`read_volatile`]: ./fn.read_volatile.html +//! [`write_volatile`]: ./fn.write_volatile.html //! [`NonNull::dangling`]: ./struct.NonNull.html#method.dangling #![stable(feature = "rust1", since = "1.0.0")] From 78f5b6866efb2445b2b7ea306cb9660a94fb58f0 Mon Sep 17 00:00:00 2001 From: Nicole Mazzuca Date: Mon, 10 Sep 2018 22:30:30 -0700 Subject: [PATCH 29/33] fix typos --- src/libcore/intrinsics.rs | 2 +- src/libcore/ptr.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 659b7a23ed922..823678ec88020 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1159,7 +1159,7 @@ extern "rust-intrinsic" { /// // At this point, using or dropping `v` results in undefined behavior. /// // drop(v); // ERROR /// - /// // Even leaking `v` "uses" it, and henc eis undefined behavior. + /// // Even leaking `v` "uses" it, and hence is undefined behavior. /// // mem::forget(v); // ERROR /// /// unsafe { diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 5c16c8acae596..defe3d807faeb 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -47,7 +47,7 @@ //! ## Alignment //! //! Valid raw pointers as defined above are not necessarily properly aligned (where -//! "proper" alignment is defind by the pointee type, i.e., `*const T` must be +//! "proper" alignment is defined by the pointee type, i.e., `*const T` must be //! aligned to `mem::align_of::()`). However, most functions require their //! arguments to be properly aligned, and will explicitly state //! this requirement in their documentation. Notable exceptions to this are From 2713d3667927e2633098d16c5bb764c789bc7775 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 17 Sep 2018 15:14:19 +0200 Subject: [PATCH 30/33] tweaks --- src/libcore/intrinsics.rs | 6 +++--- src/libcore/ptr.rs | 25 ++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 823678ec88020..e6e830b1b6c85 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1118,7 +1118,7 @@ extern "rust-intrinsic" { /// /// * `dst` must be properly aligned. /// - /// Additionally, the caller should ensure that writing `count * + /// Additionally, the caller must ensure that writing `count * /// size_of::()` bytes to the given region of memory results in a valid /// value of `T`. Using a region of memory typed as a `T` that contains an /// invalid value of `T` is undefined behavior. @@ -1153,7 +1153,7 @@ extern "rust-intrinsic" { /// unsafe { /// // Leaks the previously held value by overwriting the `Box` with /// // a null pointer. - /// ptr::write_bytes(&mut v, 0, 1); + /// ptr::write_bytes(&mut v as *mut Box, 0, 1); /// } /// /// // At this point, using or dropping `v` results in undefined behavior. @@ -1164,7 +1164,7 @@ extern "rust-intrinsic" { /// /// unsafe { /// // Let us instead put in a valid value - /// ptr::write(&mut v, Box::new(42i32)); + /// ptr::write(&mut v as *mut Box, Box::new(42i32)); /// } /// /// // Now the box is fine diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index defe3d807faeb..68082e3ae8090 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -117,7 +117,6 @@ pub use intrinsics::write_bytes; /// /// * `to_drop` must be properly aligned. See the example below for how to drop /// an unaligned pointer. - /// /// Additionally, if `T` is not [`Copy`], using the pointed-to value after /// calling `drop_in_place` can cause undefined behavior. Note that `*to_drop = @@ -185,6 +184,10 @@ pub use intrinsics::write_bytes; /// mem::forget(p); /// } /// ``` +/// +/// Notice that the compiler performs this copy automatically when dropping packed structs, +/// i.e., you do not usually have to worry about such issues unless you call `drop_in_place` +/// manually. #[stable(feature = "drop_in_place", since = "1.8.0")] #[lang = "drop_in_place"] #[allow(unconditional_recursion)] @@ -547,6 +550,9 @@ pub unsafe fn replace(dst: *mut T, mut src: T) -> T { /// /// // Move `tmp` into `b`. /// ptr::write(b, tmp); +/// +/// // `tmp` has been moved (`write` takes ownership of its second argument), +/// // so nothing is dropped implicitly here. /// } /// } /// @@ -688,9 +694,26 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// /// 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); +/// +/// // `tmp` has been moved (`write` takes ownership of its second argument), +/// // so nothing is dropped implicitly here. /// } /// } /// From 0ec87d0c928d04b57a3a073195f4095e64b8e867 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 17 Sep 2018 15:21:20 +0200 Subject: [PATCH 31/33] rearrange for clarity --- src/libcore/ptr.rs | 81 +++++++++++++++++++++++----------------------- 1 file changed, 40 insertions(+), 41 deletions(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 68082e3ae8090..5910ba2fd0105 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -472,47 +472,6 @@ pub unsafe fn replace(dst: *mut T, mut src: T) -> T { /// /// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. /// -/// ## 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::from("foo"); -/// unsafe { -/// // `s2` now points to the same underlying memory as `s`. -/// let mut s2: String = 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(); -/// assert_eq!(s2, ""); -/// -/// // Assigning to `s` would cause the old value to be dropped again, -/// // resulting in undefined behavior. -/// // s = String::from("bar"); // ERROR -/// -/// // `ptr::write` can be used to overwrite a value without dropping it. -/// ptr::write(&mut s, String::from("bar")); -/// } -/// -/// assert_eq!(s, "bar"); -/// ``` -/// /// # Examples /// /// Basic usage: @@ -565,7 +524,47 @@ pub unsafe fn replace(dst: *mut T, mut src: T) -> T { /// assert_eq!(bar, "foo"); /// ``` /// +/// ## 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. +/// +/// ``` +/// use std::ptr; +/// +/// let mut s = String::from("foo"); +/// unsafe { +/// // `s2` now points to the same underlying memory as `s`. +/// let mut s2: String = 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(); +/// assert_eq!(s2, ""); +/// +/// // Assigning to `s` would cause the old value to be dropped again, +/// // resulting in undefined behavior. +/// // s = String::from("bar"); // ERROR +/// +/// // `ptr::write` can be used to overwrite a value without dropping it. +/// ptr::write(&mut s, String::from("bar")); +/// } +/// +/// assert_eq!(s, "bar"); +/// ``` +/// /// [`mem::swap`]: ../mem/fn.swap.html +/// [valid]: ../ptr/index.html#safety +/// [`Copy`]: ../marker/trait.Copy.html +/// [`read_unaligned`]: ./fn.read_unaligned.html +/// [`write`]: ./fn.write.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn read(src: *const T) -> T { From adcc0d21687f642e3d947cd6d547bec1768c0941 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 Sep 2018 21:14:31 +0200 Subject: [PATCH 32/33] clarify swap --- src/libcore/ptr.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 5910ba2fd0105..14f2148a64e0e 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -236,7 +236,7 @@ pub const fn null_mut() -> *mut T { 0 as *mut T } /// /// * 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. +/// in the second example below. /// /// [`mem::swap`]: ../mem/fn.swap.html /// @@ -261,8 +261,8 @@ pub const fn null_mut() -> *mut T { 0 as *mut T } /// /// let mut array = [0, 1, 2, 3]; /// -/// let x = array[0..].as_mut_ptr() as *mut [u32; 2]; -/// let y = array[2..].as_mut_ptr() as *mut [u32; 2]; +/// let x = array[0..].as_mut_ptr() as *mut [u32; 2]; // this is `array[0..2]` +/// let y = array[2..].as_mut_ptr() as *mut [u32; 2]; // this is `array[2..4]` /// /// unsafe { /// ptr::swap(x, y); @@ -277,11 +277,16 @@ pub const fn null_mut() -> *mut T { 0 as *mut T } /// /// let mut array = [0, 1, 2, 3]; /// -/// let x = array[0..].as_mut_ptr() as *mut [u32; 3]; -/// let y = array[1..].as_mut_ptr() as *mut [u32; 3]; +/// let x = array[0..].as_mut_ptr() as *mut [u32; 3]; // this is `array[0..3]` +/// let y = array[1..].as_mut_ptr() as *mut [u32; 3]; // this is `array[1..4]` /// /// unsafe { /// ptr::swap(x, y); +/// // The indices `1..3` of the slice overlap between `x` and `y`. +/// // Reasonable results would be for to them be `[2, 3]`, so that indices `0..3` are +/// // `[1, 2, 3]` (matching `y` before the `swap`); or for them to be `[0, 1]` +/// // so that indices `1..4` are `[0, 1, 2]` (matching `x` before the `swap`). +/// // This implementation is defined to make the latter choice. /// assert_eq!([1, 0, 1, 2], array); /// } /// ``` From c197dc467fc18c3923f27c8e57e174497f2e63ed Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 21 Sep 2018 16:01:58 +0200 Subject: [PATCH 33/33] clarify write_bytes a bit --- src/libcore/intrinsics.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index e6e830b1b6c85..56a24168e28d9 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1162,6 +1162,10 @@ extern "rust-intrinsic" { /// // Even leaking `v` "uses" it, and hence is undefined behavior. /// // mem::forget(v); // ERROR /// + /// // In fact, `v` is invalid according to basic type layout invariants, so *any* + /// // operation touching it is undefined behavior. + /// // let v2 = v; // ERROR + /// /// unsafe { /// // Let us instead put in a valid value /// ptr::write(&mut v as *mut Box, Box::new(42i32));