From a7e1431941406eeb341c4e3b7e929c2e65514ac3 Mon Sep 17 00:00:00 2001 From: Brent Kerby Date: Sun, 19 May 2019 09:21:03 -0600 Subject: [PATCH 1/3] Update boxed::Box docs on memory layout --- src/liballoc/boxed.rs | 63 ++++++++++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 16 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 207359ed696..90bec03beb0 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -127,24 +127,38 @@ impl Box { /// /// After calling this function, the raw pointer is owned by the /// resulting `Box`. Specifically, the `Box` destructor will call - /// the destructor of `T` and free the allocated memory. Since the - /// way `Box` allocates and releases memory is unspecified, the - /// only valid pointer to pass to this function is the one taken - /// from another `Box` via the [`Box::into_raw`] function. + /// the destructor of `T` and free the allocated memory. For this + /// to be safe, the memory must have been allocated in the precise + /// way that `Box` expects, namely, using the global allocator + /// with the correct [`Layout`] for holding a value of type `T`. In + /// particular, this will be satisfied for a pointer obtained + /// from a previously existing `Box` using [`Box::into_raw`]. + /// + /// # Safety /// /// This function is unsafe because improper use may lead to /// memory problems. For example, a double-free may occur if the /// function is called twice on the same raw pointer. /// - /// [`Box::into_raw`]: struct.Box.html#method.into_raw - /// /// # Examples - /// + /// Recreate a `Box` which was previously converted to a raw pointer using [`Box::into_raw`]: /// ``` /// let x = Box::new(5); /// let ptr = Box::into_raw(x); /// let x = unsafe { Box::from_raw(ptr) }; /// ``` + /// Manually create a `Box` from scratch by using the global allocator: + /// ``` + /// use std::alloc::{Layout, alloc}; + /// + /// let ptr = unsafe{ alloc(Layout::new::()) } as *mut i32; + /// unsafe{ *ptr = 5; } + /// let x = unsafe{ Box::from_raw(ptr) }; + /// ``` + /// + /// [`Layout`]: ../alloc/struct.Layout.html + /// [`Box::into_raw`]: struct.Box.html#method.into_raw + /// #[stable(feature = "box_raw", since = "1.4.0")] #[inline] pub unsafe fn from_raw(raw: *mut T) -> Self { @@ -158,21 +172,34 @@ impl Box { /// After calling this function, the caller is responsible for the /// memory previously managed by the `Box`. In particular, the /// caller should properly destroy `T` and release the memory. The - /// proper way to do so is to convert the raw pointer back into a - /// `Box` with the [`Box::from_raw`] function. + /// easiest way to do so is to convert the raw pointer back into a `Box` + /// with the [`Box::from_raw`] function. /// /// Note: this is an associated function, which means that you have /// to call it as `Box::into_raw(b)` instead of `b.into_raw()`. This /// is so that there is no conflict with a method on the inner type. /// + /// # Examples + /// Converting the raw pointer back into a `Box` with [`Box::from_raw`] + /// for automatic cleanup: + /// ``` + /// let x = Box::new(String::from("Hello")); + /// let ptr = Box::into_raw(x); + /// let x = unsafe{ Box::from_raw(ptr) }; + /// ``` + /// Manual cleanup by running the destructor and deallocating the memory: + /// ``` + /// use std::alloc::{Layout, dealloc}; + /// use std::ptr; + /// + /// let x = Box::new(String::from("Hello")); + /// let p = Box::into_raw(x); + /// unsafe{ ptr::drop_in_place(p); } + /// unsafe{ dealloc(p as *mut u8, Layout::new::()); } + /// ``` + /// /// [`Box::from_raw`]: struct.Box.html#method.from_raw /// - /// # Examples - /// - /// ``` - /// let x = Box::new(5); - /// let ptr = Box::into_raw(x); - /// ``` #[stable(feature = "box_raw", since = "1.4.0")] #[inline] pub fn into_raw(b: Box) -> *mut T { @@ -184,7 +211,7 @@ impl Box { /// After calling this function, the caller is responsible for the /// memory previously managed by the `Box`. In particular, the /// caller should properly destroy `T` and release the memory. The - /// proper way to do so is to convert the `NonNull` pointer + /// easiest way to do so is to convert the `NonNull` pointer /// into a raw pointer and back into a `Box` with the [`Box::from_raw`] /// function. /// @@ -203,6 +230,10 @@ impl Box { /// fn main() { /// let x = Box::new(5); /// let ptr = Box::into_raw_non_null(x); + /// + /// // Clean up the memory by converting the NonNull pointer back + /// // into a Box and letting the Box be dropped. + /// let x = unsafe{ Box::from_raw(ptr.as_ptr()) }; /// } /// ``` #[unstable(feature = "box_into_raw_non_null", issue = "47336")] From 178b753a4a202ad96ccbd10e037194d15ca8f805 Mon Sep 17 00:00:00 2001 From: Brent Kerby Date: Sun, 19 May 2019 17:47:18 -0600 Subject: [PATCH 2/3] Remove trailing whitespaces to satisfy tidy --- src/liballoc/boxed.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 90bec03beb0..4e712a946b8 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -130,9 +130,9 @@ impl Box { /// the destructor of `T` and free the allocated memory. For this /// to be safe, the memory must have been allocated in the precise /// way that `Box` expects, namely, using the global allocator - /// with the correct [`Layout`] for holding a value of type `T`. In + /// with the correct [`Layout`] for holding a value of type `T`. In /// particular, this will be satisfied for a pointer obtained - /// from a previously existing `Box` using [`Box::into_raw`]. + /// from a previously existing `Box` using [`Box::into_raw`]. /// /// # Safety /// @@ -172,7 +172,7 @@ impl Box { /// After calling this function, the caller is responsible for the /// memory previously managed by the `Box`. In particular, the /// caller should properly destroy `T` and release the memory. The - /// easiest way to do so is to convert the raw pointer back into a `Box` + /// easiest way to do so is to convert the raw pointer back into a `Box` /// with the [`Box::from_raw`] function. /// /// Note: this is an associated function, which means that you have @@ -180,7 +180,7 @@ impl Box { /// is so that there is no conflict with a method on the inner type. /// /// # Examples - /// Converting the raw pointer back into a `Box` with [`Box::from_raw`] + /// Converting the raw pointer back into a `Box` with [`Box::from_raw`] /// for automatic cleanup: /// ``` /// let x = Box::new(String::from("Hello")); @@ -191,7 +191,7 @@ impl Box { /// ``` /// use std::alloc::{Layout, dealloc}; /// use std::ptr; - /// + /// /// let x = Box::new(String::from("Hello")); /// let p = Box::into_raw(x); /// unsafe{ ptr::drop_in_place(p); } From 4e37785c7d6ef85d00833e93943cdee28baf97b3 Mon Sep 17 00:00:00 2001 From: Brent Kerby Date: Mon, 20 May 2019 21:03:40 -0600 Subject: [PATCH 3/3] Create and reference Memory Layout section of boxed docs --- src/liballoc/boxed.rs | 70 ++++++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 31 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 4e712a946b8..024594517d9 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -4,16 +4,6 @@ //! heap allocation in Rust. Boxes provide ownership for this allocation, and //! drop their contents when they go out of scope. //! -//! For non-zero-sized values, a [`Box`] will use the [`Global`] allocator for -//! its allocation. It is valid to convert both ways between a [`Box`] and a -//! raw pointer allocated with the [`Global`] allocator, given that the -//! [`Layout`] used with the allocator is correct for the type. More precisely, -//! a `value: *mut T` that has been allocated with the [`Global`] allocator -//! with `Layout::for_value(&*value)` may be converted into a box using -//! `Box::::from_raw(value)`. Conversely, the memory backing a `value: *mut -//! T` obtained from `Box::::into_raw` may be deallocated using the -//! [`Global`] allocator with `Layout::for_value(&*value)`. -//! //! # Examples //! //! Move a value from the stack to the heap by creating a [`Box`]: @@ -61,6 +51,19 @@ //! for a `Cons`. By introducing a `Box`, which has a defined size, we know how //! big `Cons` needs to be. //! +//! # Memory layout +//! +//! For non-zero-sized values, a [`Box`] will use the [`Global`] allocator for +//! its allocation. It is valid to convert both ways between a [`Box`] and a +//! raw pointer allocated with the [`Global`] allocator, given that the +//! [`Layout`] used with the allocator is correct for the type. More precisely, +//! a `value: *mut T` that has been allocated with the [`Global`] allocator +//! with `Layout::for_value(&*value)` may be converted into a box using +//! `Box::::from_raw(value)`. Conversely, the memory backing a `value: *mut +//! T` obtained from `Box::::into_raw` may be deallocated using the +//! [`Global`] allocator with `Layout::for_value(&*value)`. +//! +//! //! [dereferencing]: ../../std/ops/trait.Deref.html //! [`Box`]: struct.Box.html //! [`Global`]: ../alloc/struct.Global.html @@ -128,11 +131,8 @@ impl Box { /// After calling this function, the raw pointer is owned by the /// resulting `Box`. Specifically, the `Box` destructor will call /// the destructor of `T` and free the allocated memory. For this - /// to be safe, the memory must have been allocated in the precise - /// way that `Box` expects, namely, using the global allocator - /// with the correct [`Layout`] for holding a value of type `T`. In - /// particular, this will be satisfied for a pointer obtained - /// from a previously existing `Box` using [`Box::into_raw`]. + /// to be safe, the memory must have been allocated in accordance + /// with the [memory layout] used by `Box` . /// /// # Safety /// @@ -141,7 +141,8 @@ impl Box { /// function is called twice on the same raw pointer. /// /// # Examples - /// Recreate a `Box` which was previously converted to a raw pointer using [`Box::into_raw`]: + /// Recreate a `Box` which was previously converted to a raw pointer + /// using [`Box::into_raw`]: /// ``` /// let x = Box::new(5); /// let ptr = Box::into_raw(x); @@ -149,16 +150,18 @@ impl Box { /// ``` /// Manually create a `Box` from scratch by using the global allocator: /// ``` - /// use std::alloc::{Layout, alloc}; + /// use std::alloc::{alloc, Layout}; /// - /// let ptr = unsafe{ alloc(Layout::new::()) } as *mut i32; - /// unsafe{ *ptr = 5; } - /// let x = unsafe{ Box::from_raw(ptr) }; + /// unsafe { + /// let ptr = alloc(Layout::new::()) as *mut i32; + /// *ptr = 5; + /// let x = Box::from_raw(ptr); + /// } /// ``` /// + /// [memory layout]: index.html#memory-layout /// [`Layout`]: ../alloc/struct.Layout.html /// [`Box::into_raw`]: struct.Box.html#method.into_raw - /// #[stable(feature = "box_raw", since = "1.4.0")] #[inline] pub unsafe fn from_raw(raw: *mut T) -> Self { @@ -171,9 +174,11 @@ impl Box { /// /// After calling this function, the caller is responsible for the /// memory previously managed by the `Box`. In particular, the - /// caller should properly destroy `T` and release the memory. The - /// easiest way to do so is to convert the raw pointer back into a `Box` - /// with the [`Box::from_raw`] function. + /// caller should properly destroy `T` and release the memory, taking + /// into account the [memory layout] used by `Box`. The easiest way to + /// do this is to convert the raw pointer back into a `Box` with the + /// [`Box::from_raw`] function, allowing the `Box` destructor to perform + /// the cleanup. /// /// Note: this is an associated function, which means that you have /// to call it as `Box::into_raw(b)` instead of `b.into_raw()`. This @@ -185,21 +190,24 @@ impl Box { /// ``` /// let x = Box::new(String::from("Hello")); /// let ptr = Box::into_raw(x); - /// let x = unsafe{ Box::from_raw(ptr) }; + /// let x = unsafe { Box::from_raw(ptr) }; /// ``` - /// Manual cleanup by running the destructor and deallocating the memory: + /// Manual cleanup by explicitly running the destructor and deallocating + /// the memory: /// ``` - /// use std::alloc::{Layout, dealloc}; + /// use std::alloc::{dealloc, Layout}; /// use std::ptr; /// /// let x = Box::new(String::from("Hello")); /// let p = Box::into_raw(x); - /// unsafe{ ptr::drop_in_place(p); } - /// unsafe{ dealloc(p as *mut u8, Layout::new::()); } + /// unsafe { + /// ptr::drop_in_place(p); + /// dealloc(p as *mut u8, Layout::new::()); + /// } /// ``` /// + /// [memory layout]: index.html#memory-layout /// [`Box::from_raw`]: struct.Box.html#method.from_raw - /// #[stable(feature = "box_raw", since = "1.4.0")] #[inline] pub fn into_raw(b: Box) -> *mut T { @@ -233,7 +241,7 @@ impl Box { /// /// // Clean up the memory by converting the NonNull pointer back /// // into a Box and letting the Box be dropped. - /// let x = unsafe{ Box::from_raw(ptr.as_ptr()) }; + /// let x = unsafe { Box::from_raw(ptr.as_ptr()) }; /// } /// ``` #[unstable(feature = "box_into_raw_non_null", issue = "47336")]