@@ -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,27 +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. For example:
73
+ /// This is useful when the ownership of the underlying 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
+ /// Using `mem::forget` to transmit memory ownership is error-prone and is best
80
+ /// replaced with `ManuallyDrop`. Consider, for example, this code:
73
81
///
74
82
/// ```
75
83
/// use std::mem;
76
84
///
77
85
/// let mut v = vec![65, 122];
78
86
/// // Build a `String` using the contents of `v`
79
87
/// let s = unsafe { String::from_raw_parts(v.as_mut_ptr(), 2, v.capacity()) };
80
- /// // immediately leak `v` because its memory is now managed by `s`
81
- /// mem::forget(v);
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
82
90
/// assert_eq!(s, "Az");
83
91
/// // `s` is implicitly dropped and its memory deallocated.
84
92
/// ```
85
93
///
86
- /// The above is correct, but brittle. If code gets added between the construction of
87
- /// `String` and the invocation of `mem::forget()`, a panic within it will cause a double
88
- /// free because the same memory is handled by both `v` and `s`. This can be fixed by
89
- /// storing the result of `v.as_mut_ptr()` in a local variable and calling `mem::forget()`
90
- /// before `String::from_raw_parts`. This kind of issue can be more robustly prevented by
91
- /// using [`ManuallyDrop`], which is usually preferred for such cases:
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. Although moving a value to `mem::forget` (which won't
101
+ /// inspect it) seems safe, 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:
92
107
///
93
108
/// ```
94
109
/// use std::mem::ManuallyDrop;
@@ -108,12 +123,15 @@ pub use crate::intrinsics::transmute;
108
123
///
109
124
/// `ManuallyDrop` robustly prevents double-free because we disable `v`'s destructor
110
125
/// before doing anything else. `mem::forget()` doesn't allow this because it consumes its
111
- /// argument, forcing us to call it only after extracting anything we need from `v`.
112
- ///
113
- /// Note that the above code cannot panic between construction of `ManuallyDrop` and
114
- /// building the string. But even if it could (after a modification), a panic there would
115
- /// result in a leak and not a double free. In other words, `ManuallyDrop` errs on the
116
- /// side of leaking instead of erring on the side of dropping.
126
+ /// argument, forcing us to call it only after extracting anything we need from `v`. Even
127
+ /// if a panic were introduced between construction of `ManuallyDrop` and building the
128
+ /// string (which cannot happen in the code as shown), it would result in a leak and not a
129
+ /// double free. In other words, `ManuallyDrop` errs on the side of leaking instead of
130
+ /// erring on the side of dropping.
131
+ ///
132
+ /// Also, `ManuallyDrop` prevents us from having to "touch" `v` after transferring the
133
+ /// ownership to `s` - the final step of interacting with `v` to dispoe of it without
134
+ /// running its destructor is entirely avoided.
117
135
///
118
136
/// [drop]: fn.drop.html
119
137
/// [uninit]: fn.uninitialized.html
0 commit comments