@@ -58,7 +58,9 @@ pub use crate::intrinsics::transmute;
5858///
5959/// # Examples
6060///
61- /// Leak an I/O object, never closing the file:
61+ /// The canonical safe use of `mem::forget` is to circumvent a value's destructor
62+ /// implemented by the `Drop` trait. For example, this will leak a `File`, i.e. reclaim
63+ /// the space taken by the variable but never close the underlying system resource:
6264///
6365/// ```no_run
6466/// use std::mem;
@@ -68,9 +70,40 @@ pub use crate::intrinsics::transmute;
6870/// mem::forget(file);
6971/// ```
7072///
71- /// The practical use cases for `forget` are rather specialized and mainly come
72- /// up in unsafe or FFI code. However, [`ManuallyDrop`] is usually preferred
73- /// for such cases, e.g.:
73+ /// This is useful when the ownership of the underlying resource was previously
74+ /// transferred to code outside of Rust, for example by transmitting the raw
75+ /// file descriptor to C code.
76+ ///
77+ /// # Relationship with `ManuallyDrop`
78+ ///
79+ /// While `mem::forget` can also be used to transfer *memory* ownership, doing so is error-prone.
80+ /// [`ManuallyDrop`] should be used instead. Consider, for example, this code:
81+ ///
82+ /// ```
83+ /// use std::mem;
84+ ///
85+ /// let mut v = vec![65, 122];
86+ /// // Build a `String` using the contents of `v`
87+ /// let s = unsafe { String::from_raw_parts(v.as_mut_ptr(), v.len(), v.capacity()) };
88+ /// // leak `v` because its memory is now managed by `s`
89+ /// mem::forget(v); // ERROR - v is invalid and must not be passed to a function
90+ /// assert_eq!(s, "Az");
91+ /// // `s` is implicitly dropped and its memory deallocated.
92+ /// ```
93+ ///
94+ /// There are two issues with the above example:
95+ ///
96+ /// * If more code were added between the construction of `String` and the invocation of
97+ /// `mem::forget()`, a panic within it would cause a double free because the same memory
98+ /// is handled by both `v` and `s`.
99+ /// * After calling `v.as_mut_ptr()` and transmitting the ownership of the data to `s`,
100+ /// the `v` value is invalid. Even when a value is just moved to `mem::forget` (which won't
101+ /// inspect it), some types have strict requirements on their values that
102+ /// make them invalid when dangling or no longer owned. Using invalid values in any
103+ /// way, including passing them to or returning them from functions, constitutes
104+ /// undefined behavior and may break the assumptions made by the compiler.
105+ ///
106+ /// Switching to `ManuallyDrop` avoids both issues:
74107///
75108/// ```
76109/// use std::mem::ManuallyDrop;
@@ -80,24 +113,24 @@ pub use crate::intrinsics::transmute;
80113/// // does not get dropped!
81114/// let mut v = ManuallyDrop::new(v);
82115/// // Now disassemble `v`. These operations cannot panic, so there cannot be a leak.
83- /// let ptr = v.as_mut_ptr();
84- /// let cap = v.capacity();
116+ /// let (ptr, len, cap) = (v.as_mut_ptr(), v.len(), v.capacity());
85117/// // Finally, build a `String`.
86- /// let s = unsafe { String::from_raw_parts(ptr, 2 , cap) };
118+ /// let s = unsafe { String::from_raw_parts(ptr, len , cap) };
87119/// assert_eq!(s, "Az");
88120/// // `s` is implicitly dropped and its memory deallocated.
89121/// ```
90122///
91- /// Using `ManuallyDrop` here has two advantages:
123+ /// `ManuallyDrop` robustly prevents double-free because we disable `v`'s destructor
124+ /// before doing anything else. `mem::forget()` doesn't allow this because it consumes its
125+ /// argument, forcing us to call it only after extracting anything we need from `v`. Even
126+ /// if a panic were introduced between construction of `ManuallyDrop` and building the
127+ /// string (which cannot happen in the code as shown), it would result in a leak and not a
128+ /// double free. In other words, `ManuallyDrop` errs on the side of leaking instead of
129+ /// erring on the side of (double-)dropping.
92130///
93- /// * We do not "touch" `v` after disassembling it. For some types, operations
94- /// such as passing ownership (to a function like `mem::forget`) requires them to actually
95- /// be fully owned right now; that is a promise we do not want to make here as we are
96- /// in the process of transferring ownership to the new `String` we are building.
97- /// * In case of an unexpected panic, `ManuallyDrop` is not dropped, but if the panic
98- /// occurs before `mem::forget` was called we might end up dropping invalid data,
99- /// or double-dropping. In other words, `ManuallyDrop` errs on the side of leaking
100- /// instead of erring on the side of dropping.
131+ /// Also, `ManuallyDrop` prevents us from having to "touch" `v` after transferring the
132+ /// ownership to `s` - the final step of interacting with `v` to dispoe of it without
133+ /// running its destructor is entirely avoided.
101134///
102135/// [drop]: fn.drop.html
103136/// [uninit]: fn.uninitialized.html
0 commit comments