@@ -58,7 +58,9 @@ pub use crate::intrinsics::transmute;
58
58
///
59
59
/// # Examples
60
60
///
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:
62
64
///
63
65
/// ```no_run
64
66
/// use std::mem;
@@ -68,9 +70,40 @@ pub use crate::intrinsics::transmute;
68
70
/// mem::forget(file);
69
71
/// ```
70
72
///
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:
74
107
///
75
108
/// ```
76
109
/// use std::mem::ManuallyDrop;
@@ -80,24 +113,24 @@ pub use crate::intrinsics::transmute;
80
113
/// // does not get dropped!
81
114
/// let mut v = ManuallyDrop::new(v);
82
115
/// // 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());
85
117
/// // 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) };
87
119
/// assert_eq!(s, "Az");
88
120
/// // `s` is implicitly dropped and its memory deallocated.
89
121
/// ```
90
122
///
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.
92
130
///
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.
101
134
///
102
135
/// [drop]: fn.drop.html
103
136
/// [uninit]: fn.uninitialized.html
0 commit comments