Skip to content

Commit fee76ea

Browse files
authored
chore: try to avoid noalias attributes on intrusive linked list (#3654)
1 parent 1a80d6e commit fee76ea

File tree

1 file changed

+113
-38
lines changed

1 file changed

+113
-38
lines changed

tokio/src/util/linked_list.rs

+113-38
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66
//! structure's APIs are `unsafe` as they require the caller to ensure the
77
//! specified node is actually contained by the list.
88
9+
use core::cell::UnsafeCell;
910
use core::fmt;
10-
use core::marker::PhantomData;
11+
use core::marker::{PhantomData, PhantomPinned};
1112
use core::mem::ManuallyDrop;
12-
use core::ptr::NonNull;
13+
use core::ptr::{self, NonNull};
1314

1415
/// An intrusive linked list.
1516
///
@@ -60,11 +61,40 @@ pub(crate) unsafe trait Link {
6061

6162
/// Previous / next pointers
6263
pub(crate) struct Pointers<T> {
64+
inner: UnsafeCell<PointersInner<T>>,
65+
}
66+
/// We do not want the compiler to put the `noalias` attribute on mutable
67+
/// references to this type, so the type has been made `!Unpin` with a
68+
/// `PhantomPinned` field.
69+
///
70+
/// Additionally, we never access the `prev` or `next` fields directly, as any
71+
/// such access would implicitly involve the creation of a reference to the
72+
/// field, which we want to avoid since the fields are not `!Unpin`, and would
73+
/// hence be given the `noalias` attribute if we were to do such an access.
74+
/// As an alternative to accessing the fields directly, the `Pointers` type
75+
/// provides getters and setters for the two fields, and those are implemented
76+
/// using raw pointer casts and offsets, which is valid since the struct is
77+
/// #[repr(C)].
78+
///
79+
/// See this link for more information:
80+
/// https://github.com/rust-lang/rust/pull/82834
81+
#[repr(C)]
82+
struct PointersInner<T> {
6383
/// The previous node in the list. null if there is no previous node.
84+
///
85+
/// This field is accessed through pointer manipulation, so it is not dead code.
86+
#[allow(dead_code)]
6487
prev: Option<NonNull<T>>,
6588

6689
/// The next node in the list. null if there is no previous node.
90+
///
91+
/// This field is accessed through pointer manipulation, so it is not dead code.
92+
#[allow(dead_code)]
6793
next: Option<NonNull<T>>,
94+
95+
/// This type is !Unpin due to the heuristic from:
96+
/// https://github.com/rust-lang/rust/pull/82834
97+
_pin: PhantomPinned,
6898
}
6999

70100
unsafe impl<T: Send> Send for Pointers<T> {}
@@ -91,11 +121,11 @@ impl<L: Link> LinkedList<L, L::Target> {
91121
let ptr = L::as_raw(&*val);
92122
assert_ne!(self.head, Some(ptr));
93123
unsafe {
94-
L::pointers(ptr).as_mut().next = self.head;
95-
L::pointers(ptr).as_mut().prev = None;
124+
L::pointers(ptr).as_mut().set_next(self.head);
125+
L::pointers(ptr).as_mut().set_prev(None);
96126

97127
if let Some(head) = self.head {
98-
L::pointers(head).as_mut().prev = Some(ptr);
128+
L::pointers(head).as_mut().set_prev(Some(ptr));
99129
}
100130

101131
self.head = Some(ptr);
@@ -111,16 +141,16 @@ impl<L: Link> LinkedList<L, L::Target> {
111141
pub(crate) fn pop_back(&mut self) -> Option<L::Handle> {
112142
unsafe {
113143
let last = self.tail?;
114-
self.tail = L::pointers(last).as_ref().prev;
144+
self.tail = L::pointers(last).as_ref().get_prev();
115145

116-
if let Some(prev) = L::pointers(last).as_ref().prev {
117-
L::pointers(prev).as_mut().next = None;
146+
if let Some(prev) = L::pointers(last).as_ref().get_prev() {
147+
L::pointers(prev).as_mut().set_next(None);
118148
} else {
119149
self.head = None
120150
}
121151

122-
L::pointers(last).as_mut().prev = None;
123-
L::pointers(last).as_mut().next = None;
152+
L::pointers(last).as_mut().set_prev(None);
153+
L::pointers(last).as_mut().set_next(None);
124154

125155
Some(L::from_raw(last))
126156
}
@@ -143,31 +173,35 @@ impl<L: Link> LinkedList<L, L::Target> {
143173
/// The caller **must** ensure that `node` is currently contained by
144174
/// `self` or not contained by any other list.
145175
pub(crate) unsafe fn remove(&mut self, node: NonNull<L::Target>) -> Option<L::Handle> {
146-
if let Some(prev) = L::pointers(node).as_ref().prev {
147-
debug_assert_eq!(L::pointers(prev).as_ref().next, Some(node));
148-
L::pointers(prev).as_mut().next = L::pointers(node).as_ref().next;
176+
if let Some(prev) = L::pointers(node).as_ref().get_prev() {
177+
debug_assert_eq!(L::pointers(prev).as_ref().get_next(), Some(node));
178+
L::pointers(prev)
179+
.as_mut()
180+
.set_next(L::pointers(node).as_ref().get_next());
149181
} else {
150182
if self.head != Some(node) {
151183
return None;
152184
}
153185

154-
self.head = L::pointers(node).as_ref().next;
186+
self.head = L::pointers(node).as_ref().get_next();
155187
}
156188

157-
if let Some(next) = L::pointers(node).as_ref().next {
158-
debug_assert_eq!(L::pointers(next).as_ref().prev, Some(node));
159-
L::pointers(next).as_mut().prev = L::pointers(node).as_ref().prev;
189+
if let Some(next) = L::pointers(node).as_ref().get_next() {
190+
debug_assert_eq!(L::pointers(next).as_ref().get_prev(), Some(node));
191+
L::pointers(next)
192+
.as_mut()
193+
.set_prev(L::pointers(node).as_ref().get_prev());
160194
} else {
161195
// This might be the last item in the list
162196
if self.tail != Some(node) {
163197
return None;
164198
}
165199

166-
self.tail = L::pointers(node).as_ref().prev;
200+
self.tail = L::pointers(node).as_ref().get_prev();
167201
}
168202

169-
L::pointers(node).as_mut().next = None;
170-
L::pointers(node).as_mut().prev = None;
203+
L::pointers(node).as_mut().set_next(None);
204+
L::pointers(node).as_mut().set_prev(None);
171205

172206
Some(L::from_raw(node))
173207
}
@@ -224,7 +258,7 @@ cfg_rt_multi_thread! {
224258
fn next(&mut self) -> Option<&'a T::Target> {
225259
let curr = self.curr?;
226260
// safety: the pointer references data contained by the list
227-
self.curr = unsafe { T::pointers(curr).as_ref() }.next;
261+
self.curr = unsafe { T::pointers(curr).as_ref() }.get_next();
228262

229263
// safety: the value is still owned by the linked list.
230264
Some(unsafe { &*curr.as_ptr() })
@@ -265,7 +299,7 @@ cfg_io_readiness! {
265299
fn next(&mut self) -> Option<Self::Item> {
266300
while let Some(curr) = self.curr {
267301
// safety: the pointer references data contained by the list
268-
self.curr = unsafe { T::pointers(curr).as_ref() }.next;
302+
self.curr = unsafe { T::pointers(curr).as_ref() }.get_next();
269303

270304
// safety: the value is still owned by the linked list.
271305
if (self.filter)(unsafe { &mut *curr.as_ptr() }) {
@@ -284,17 +318,58 @@ impl<T> Pointers<T> {
284318
/// Create a new set of empty pointers
285319
pub(crate) fn new() -> Pointers<T> {
286320
Pointers {
287-
prev: None,
288-
next: None,
321+
inner: UnsafeCell::new(PointersInner {
322+
prev: None,
323+
next: None,
324+
_pin: PhantomPinned,
325+
}),
326+
}
327+
}
328+
329+
fn get_prev(&self) -> Option<NonNull<T>> {
330+
// SAFETY: prev is the first field in PointersInner, which is #[repr(C)].
331+
unsafe {
332+
let inner = self.inner.get();
333+
let prev = inner as *const Option<NonNull<T>>;
334+
ptr::read(prev)
335+
}
336+
}
337+
fn get_next(&self) -> Option<NonNull<T>> {
338+
// SAFETY: next is the second field in PointersInner, which is #[repr(C)].
339+
unsafe {
340+
let inner = self.inner.get();
341+
let prev = inner as *const Option<NonNull<T>>;
342+
let next = prev.add(1);
343+
ptr::read(next)
344+
}
345+
}
346+
347+
fn set_prev(&mut self, value: Option<NonNull<T>>) {
348+
// SAFETY: prev is the first field in PointersInner, which is #[repr(C)].
349+
unsafe {
350+
let inner = self.inner.get();
351+
let prev = inner as *mut Option<NonNull<T>>;
352+
ptr::write(prev, value);
353+
}
354+
}
355+
fn set_next(&mut self, value: Option<NonNull<T>>) {
356+
// SAFETY: next is the second field in PointersInner, which is #[repr(C)].
357+
unsafe {
358+
let inner = self.inner.get();
359+
let prev = inner as *mut Option<NonNull<T>>;
360+
let next = prev.add(1);
361+
ptr::write(next, value);
289362
}
290363
}
291364
}
292365

293366
impl<T> fmt::Debug for Pointers<T> {
294367
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
368+
let prev = self.get_prev();
369+
let next = self.get_next();
295370
f.debug_struct("Pointers")
296-
.field("prev", &self.prev)
297-
.field("next", &self.next)
371+
.field("prev", &prev)
372+
.field("next", &next)
298373
.finish()
299374
}
300375
}
@@ -321,7 +396,7 @@ mod tests {
321396
}
322397

323398
unsafe fn from_raw(ptr: NonNull<Entry>) -> Pin<&'a Entry> {
324-
Pin::new(&*ptr.as_ptr())
399+
Pin::new_unchecked(&*ptr.as_ptr())
325400
}
326401

327402
unsafe fn pointers(mut target: NonNull<Entry>) -> NonNull<Pointers<Entry>> {
@@ -361,8 +436,8 @@ mod tests {
361436

362437
macro_rules! assert_clean {
363438
($e:ident) => {{
364-
assert!($e.pointers.next.is_none());
365-
assert!($e.pointers.prev.is_none());
439+
assert!($e.pointers.get_next().is_none());
440+
assert!($e.pointers.get_prev().is_none());
366441
}};
367442
}
368443

@@ -460,8 +535,8 @@ mod tests {
460535
assert_clean!(a);
461536

462537
assert_ptr_eq!(b, list.head);
463-
assert_ptr_eq!(c, b.pointers.next);
464-
assert_ptr_eq!(b, c.pointers.prev);
538+
assert_ptr_eq!(c, b.pointers.get_next());
539+
assert_ptr_eq!(b, c.pointers.get_prev());
465540

466541
let items = collect_list(&mut list);
467542
assert_eq!([31, 7].to_vec(), items);
@@ -476,8 +551,8 @@ mod tests {
476551
assert!(list.remove(ptr(&b)).is_some());
477552
assert_clean!(b);
478553

479-
assert_ptr_eq!(c, a.pointers.next);
480-
assert_ptr_eq!(a, c.pointers.prev);
554+
assert_ptr_eq!(c, a.pointers.get_next());
555+
assert_ptr_eq!(a, c.pointers.get_prev());
481556

482557
let items = collect_list(&mut list);
483558
assert_eq!([31, 5].to_vec(), items);
@@ -493,7 +568,7 @@ mod tests {
493568
assert!(list.remove(ptr(&c)).is_some());
494569
assert_clean!(c);
495570

496-
assert!(b.pointers.next.is_none());
571+
assert!(b.pointers.get_next().is_none());
497572
assert_ptr_eq!(b, list.tail);
498573

499574
let items = collect_list(&mut list);
@@ -516,8 +591,8 @@ mod tests {
516591
assert_ptr_eq!(b, list.head);
517592
assert_ptr_eq!(b, list.tail);
518593

519-
assert!(b.pointers.next.is_none());
520-
assert!(b.pointers.prev.is_none());
594+
assert!(b.pointers.get_next().is_none());
595+
assert!(b.pointers.get_prev().is_none());
521596

522597
let items = collect_list(&mut list);
523598
assert_eq!([7].to_vec(), items);
@@ -536,8 +611,8 @@ mod tests {
536611
assert_ptr_eq!(a, list.head);
537612
assert_ptr_eq!(a, list.tail);
538613

539-
assert!(a.pointers.next.is_none());
540-
assert!(a.pointers.prev.is_none());
614+
assert!(a.pointers.get_next().is_none());
615+
assert!(a.pointers.get_prev().is_none());
541616

542617
let items = collect_list(&mut list);
543618
assert_eq!([5].to_vec(), items);

0 commit comments

Comments
 (0)