Skip to content

Commit 8b09d04

Browse files
committed
fix LinkedList invalidating mutable references
1 parent be1dbaf commit 8b09d04

File tree

1 file changed

+37
-11
lines changed

1 file changed

+37
-11
lines changed

src/liballoc/collections/linked_list.rs

+37-11
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ impl<T> Clone for Iter<'_, T> {
8686
/// [`LinkedList`]: struct.LinkedList.html
8787
#[stable(feature = "rust1", since = "1.0.0")]
8888
pub struct IterMut<'a, T: 'a> {
89+
// We do *not* exclusively own the entire list here, references to node's `element`
90+
// have been handed out by the iterator! So be careful when using this; the methods
91+
// called must be aware that there can be aliasing pointers to `element`.
8992
list: &'a mut LinkedList<T>,
9093
head: Option<NonNull<Node<T>>>,
9194
tail: Option<NonNull<Node<T>>>,
@@ -143,14 +146,17 @@ impl<T> LinkedList<T> {
143146
/// Adds the given node to the front of the list.
144147
#[inline]
145148
fn push_front_node(&mut self, mut node: Box<Node<T>>) {
149+
// This method takes care not to create mutable references to whole nodes,
150+
// to maintain validity of aliasing pointers into `element`.
146151
unsafe {
147152
node.next = self.head;
148153
node.prev = None;
149154
let node = Some(Box::into_raw_non_null(node));
150155

151156
match self.head {
152157
None => self.tail = node,
153-
Some(mut head) => head.as_mut().prev = node,
158+
// Not creating new mutable (unique!) references overlapping `element`.
159+
Some(head) => (*head.as_ptr()).prev = node,
154160
}
155161

156162
self.head = node;
@@ -161,13 +167,16 @@ impl<T> LinkedList<T> {
161167
/// Removes and returns the node at the front of the list.
162168
#[inline]
163169
fn pop_front_node(&mut self) -> Option<Box<Node<T>>> {
170+
// This method takes care not to create mutable references to whole nodes,
171+
// to maintain validity of aliasing pointers into `element`.
164172
self.head.map(|node| unsafe {
165173
let node = Box::from_raw(node.as_ptr());
166174
self.head = node.next;
167175

168176
match self.head {
169177
None => self.tail = None,
170-
Some(mut head) => head.as_mut().prev = None,
178+
// Not creating new mutable (unique!) references overlapping `element`.
179+
Some(head) => (*head.as_ptr()).prev = None,
171180
}
172181

173182
self.len -= 1;
@@ -178,14 +187,17 @@ impl<T> LinkedList<T> {
178187
/// Adds the given node to the back of the list.
179188
#[inline]
180189
fn push_back_node(&mut self, mut node: Box<Node<T>>) {
190+
// This method takes care not to create mutable references to whole nodes,
191+
// to maintain validity of aliasing pointers into `element`.
181192
unsafe {
182193
node.next = None;
183194
node.prev = self.tail;
184195
let node = Some(Box::into_raw_non_null(node));
185196

186197
match self.tail {
187198
None => self.head = node,
188-
Some(mut tail) => tail.as_mut().next = node,
199+
// Not creating new mutable (unique!) references overlapping `element`.
200+
Some(tail) => (*tail.as_ptr()).next = node,
189201
}
190202

191203
self.tail = node;
@@ -196,13 +208,16 @@ impl<T> LinkedList<T> {
196208
/// Removes and returns the node at the back of the list.
197209
#[inline]
198210
fn pop_back_node(&mut self) -> Option<Box<Node<T>>> {
211+
// This method takes care not to create mutable references to whole nodes,
212+
// to maintain validity of aliasing pointers into `element`.
199213
self.tail.map(|node| unsafe {
200214
let node = Box::from_raw(node.as_ptr());
201215
self.tail = node.prev;
202216

203217
match self.tail {
204218
None => self.head = None,
205-
Some(mut tail) => tail.as_mut().next = None,
219+
// Not creating new mutable (unique!) references overlapping `element`.
220+
Some(tail) => (*tail.as_ptr()).next = None,
206221
}
207222

208223
self.len -= 1;
@@ -213,18 +228,22 @@ impl<T> LinkedList<T> {
213228
/// Unlinks the specified node from the current list.
214229
///
215230
/// Warning: this will not check that the provided node belongs to the current list.
231+
///
232+
/// This method takes care not to create mutable references to `element`, to
233+
/// maintain validity of aliasing pointers.
216234
#[inline]
217235
unsafe fn unlink_node(&mut self, mut node: NonNull<Node<T>>) {
218-
let node = node.as_mut();
236+
let node = node.as_mut(); // this one is ours now, we can create an &mut.
219237

238+
// Not creating new mutable (unique!) references overlapping `element`.
220239
match node.prev {
221-
Some(mut prev) => prev.as_mut().next = node.next.clone(),
240+
Some(prev) => (*prev.as_ptr()).next = node.next.clone(),
222241
// this node is the head node
223242
None => self.head = node.next.clone(),
224243
};
225244

226245
match node.next {
227-
Some(mut next) => next.as_mut().prev = node.prev.clone(),
246+
Some(next) => (*next.as_ptr()).prev = node.prev.clone(),
228247
// this node is the tail node
229248
None => self.tail = node.prev.clone(),
230249
};
@@ -297,6 +316,8 @@ impl<T> LinkedList<T> {
297316
match self.tail {
298317
None => mem::swap(self, other),
299318
Some(mut tail) => {
319+
// `as_mut` is okay here because we have exclusive access to the entirety
320+
// of both lists.
300321
if let Some(mut other_head) = other.head.take() {
301322
unsafe {
302323
tail.as_mut().next = Some(other_head);
@@ -916,9 +937,11 @@ impl<T> IterMut<'_, T> {
916937
issue = "27794")]
917938
pub fn insert_next(&mut self, element: T) {
918939
match self.head {
940+
// `push_back` is okay with aliasing `element` references
919941
None => self.list.push_back(element),
920-
Some(mut head) => unsafe {
921-
let mut prev = match head.as_ref().prev {
942+
Some(head) => unsafe {
943+
let prev = match head.as_ref().prev {
944+
// `push_front` is okay with aliasing nodes
922945
None => return self.list.push_front(element),
923946
Some(prev) => prev,
924947
};
@@ -929,8 +952,10 @@ impl<T> IterMut<'_, T> {
929952
element,
930953
}));
931954

932-
prev.as_mut().next = node;
933-
head.as_mut().prev = node;
955+
// Not creating references to entire nodes to not invalidate the
956+
// reference to `element` we handed to the user.
957+
(*prev.as_ptr()).next = node;
958+
(*head.as_ptr()).prev = node;
934959

935960
self.list.len += 1;
936961
},
@@ -994,6 +1019,7 @@ impl<T, F> Iterator for DrainFilter<'_, T, F>
9941019
self.idx += 1;
9951020

9961021
if (self.pred)(&mut node.as_mut().element) {
1022+
// `unlink_node` is okay with aliasing `element` references.
9971023
self.list.unlink_node(node);
9981024
return Some(Box::from_raw(node.as_ptr()).element);
9991025
}

0 commit comments

Comments
 (0)