1
1
use crate :: ops:: { Deref , DerefMut , DerefPure } ;
2
2
use crate :: ptr;
3
3
4
- /// A wrapper to inhibit the compiler from automatically calling `T`’s destructor.
5
- /// This wrapper is 0-cost.
4
+ /// A wrapper to inhibit the compiler from automatically calling `T`’s
5
+ /// destructor. This wrapper is 0-cost.
6
6
///
7
7
/// `ManuallyDrop<T>` is guaranteed to have the same layout and bit validity as
8
- /// `T`, and is subject to the same layout optimizations as `T`. As a consequence,
9
- /// it has *no effect* on the assumptions that the compiler makes about its
10
- /// contents. For example, initializing a `ManuallyDrop<&mut T>` with [`mem::zeroed`]
11
- /// is undefined behavior. If you need to handle uninitialized data, use
12
- /// [`MaybeUninit<T>`] instead.
8
+ /// `T`, and is subject to the same layout optimizations as `T`. As a
9
+ /// consequence, it has *no effect* on the assumptions that the compiler makes
10
+ /// about its contents. For example, initializing a `ManuallyDrop<&mut T>` with
11
+ /// [`mem::zeroed`] is undefined behavior. If you need to handle uninitialized
12
+ /// data, use [`MaybeUninit<T>`] instead.
13
13
///
14
- /// Note that accessing the value inside a `ManuallyDrop<T>` is safe.
15
- /// This means that a `ManuallyDrop<T>` whose content has been dropped must not
16
- /// be exposed through a public safe API.
17
- /// Correspondingly, `ManuallyDrop::drop` is unsafe.
14
+ /// Note that accessing the value inside a `ManuallyDrop<T>` is safe. This means
15
+ /// that a `ManuallyDrop<T>` whose content has been dropped must not be exposed
16
+ /// through a public safe API. Correspondingly, `ManuallyDrop::drop` is unsafe.
18
17
///
19
- /// # `ManuallyDrop` and drop order.
18
+ /// # `ManuallyDrop` and drop order
20
19
///
21
20
/// Rust has a well-defined [drop order] of values. To make sure that fields or
22
21
/// locals are dropped in a specific order, reorder the declarations such that
@@ -40,9 +39,116 @@ use crate::ptr;
40
39
/// }
41
40
/// ```
42
41
///
42
+ /// # Interaction with `Box`
43
+ ///
44
+ /// Currently, if you have a `ManuallyDrop<T>`, where the type `T` is a `Box` or
45
+ /// contains a `Box` inside, then dropping the `T` followed by moving the
46
+ /// `ManuallyDrop<T>` is [considered to be undefined
47
+ /// behavior](https://github.com/rust-lang/unsafe-code-guidelines/issues/245).
48
+ /// That is, the following code causes undefined behavior:
49
+ ///
50
+ /// ```no_run
51
+ /// use std::mem::ManuallyDrop;
52
+ ///
53
+ /// let mut x = ManuallyDrop::new(Box::new(42));
54
+ /// unsafe {
55
+ /// ManuallyDrop::drop(&mut x);
56
+ /// }
57
+ /// let y = x; // Undefined behavior!
58
+ /// ```
59
+ ///
60
+ /// This is [likely to change in the
61
+ /// future](https://rust-lang.github.io/rfcs/3336-maybe-dangling.html). In the
62
+ /// meantime, consider using [`MaybeUninit`] instead.
63
+ ///
64
+ /// # Safety hazards when storing `ManuallyDrop` in a struct or an enum.
65
+ ///
66
+ /// Special care is needed when all of the conditions below are met:
67
+ /// * A struct or enum contains a `ManuallyDrop`.
68
+ /// * The `ManuallyDrop` is not inside a `union`.
69
+ /// * The struct or enum is part of public API, or is stored in a struct or an
70
+ /// enum that is part of public API.
71
+ /// * There is code that drops the contents of the `ManuallyDrop` field, and
72
+ /// this code is outside the struct or enum's `Drop` implementation.
73
+ ///
74
+ /// In particular, the following hazards may occur:
75
+ ///
76
+ /// #### Storing generic types
77
+ ///
78
+ /// If the `ManuallyDrop` contains a client-supplied generic type, the client
79
+ /// might provide a `Box` as that type. This would cause undefined behavior when
80
+ /// the struct or enum is later moved, as mentioned in the previous section. For
81
+ /// example, the following code causes undefined behavior:
82
+ ///
83
+ /// ```no_run
84
+ /// use std::mem::ManuallyDrop;
85
+ ///
86
+ /// pub struct BadOption<T> {
87
+ /// // Invariant: Has been dropped iff `is_some` is false.
88
+ /// value: ManuallyDrop<T>,
89
+ /// is_some: bool,
90
+ /// }
91
+ /// impl<T> BadOption<T> {
92
+ /// pub fn new(value: T) -> Self {
93
+ /// Self { value: ManuallyDrop::new(value), is_some: true }
94
+ /// }
95
+ /// pub fn change_to_none(&mut self) {
96
+ /// if self.is_some {
97
+ /// self.is_some = false;
98
+ /// unsafe {
99
+ /// // SAFETY: `value` hasn't been dropped yet, as per the invariant
100
+ /// // (This is actually unsound!)
101
+ /// ManuallyDrop::drop(&mut self.value);
102
+ /// }
103
+ /// }
104
+ /// }
105
+ /// }
106
+ ///
107
+ /// // In another crate:
108
+ ///
109
+ /// let mut option = BadOption::new(Box::new(42));
110
+ /// option.change_to_none();
111
+ /// let option2 = option; // Undefined behavior!
112
+ /// ```
113
+ ///
114
+ /// #### Deriving traits
115
+ ///
116
+ /// Deriving `Debug`, `Clone`, `PartialEq`, `PartialOrd`, `Ord`, or `Hash` on
117
+ /// the struct or enum could be unsound, since the derived implementations of
118
+ /// these traits would access the `ManuallyDrop` field. For example, the
119
+ /// following code causes undefined behavior:
120
+ ///
121
+ /// ```no_run
122
+ /// use std::mem::ManuallyDrop;
123
+ ///
124
+ /// // This derive is unsound in combination with the `ManuallyDrop::drop` call.
125
+ /// #[derive(Debug)]
126
+ /// pub struct Foo {
127
+ /// value: ManuallyDrop<String>,
128
+ /// }
129
+ /// impl Foo {
130
+ /// pub fn new() -> Self {
131
+ /// let mut temp = Self {
132
+ /// value: ManuallyDrop::new(String::from("Unsafe rust is hard."))
133
+ /// };
134
+ /// unsafe {
135
+ /// // SAFETY: `value` hasn't been dropped yet.
136
+ /// ManuallyDrop::drop(&mut temp.value);
137
+ /// }
138
+ /// temp
139
+ /// }
140
+ /// }
141
+ ///
142
+ /// // In another crate:
143
+ ///
144
+ /// let foo = Foo::new();
145
+ /// println!("{:?}", foo); // Undefined behavior!
146
+ /// ```
147
+ ///
43
148
/// [drop order]: https://doc.rust-lang.org/reference/destructors.html
44
149
/// [`mem::zeroed`]: crate::mem::zeroed
45
150
/// [`MaybeUninit<T>`]: crate::mem::MaybeUninit
151
+ /// [`MaybeUninit`]: crate::mem::MaybeUninit
46
152
#[ stable( feature = "manually_drop" , since = "1.20.0" ) ]
47
153
#[ lang = "manually_drop" ]
48
154
#[ derive( Copy , Clone , Debug , Default , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
0 commit comments