diff --git a/library/std/src/sys/sgx/abi/mod.rs b/library/std/src/sys/sgx/abi/mod.rs index b0693b63a48fd..a0eb12c3d154a 100644 --- a/library/std/src/sys/sgx/abi/mod.rs +++ b/library/std/src/sys/sgx/abi/mod.rs @@ -45,7 +45,7 @@ unsafe extern "C" fn tcs_init(secondary: bool) { // We need to wait until the initialization is done. BUSY => { while RELOC_STATE.load(Ordering::Acquire) == BUSY { - core::arch::x86_64::_mm_pause() + core::hint::spin_loop(); } } // Initialization is done. diff --git a/library/std/src/sys/sgx/abi/tls.rs b/library/std/src/sys/sgx/abi/tls.rs index 0d8952b2f273b..13d96e9a633d3 100644 --- a/library/std/src/sys/sgx/abi/tls.rs +++ b/library/std/src/sys/sgx/abi/tls.rs @@ -87,18 +87,21 @@ impl Tls { } pub unsafe fn activate(&self) -> ActiveTls<'_> { - set_tls_ptr(self as *const Tls as _); + // FIXME: Needs safety information. See entry.S for `set_tls_ptr` definition. + unsafe { set_tls_ptr(self as *const Tls as _) }; ActiveTls { tls: self } } #[allow(unused)] pub unsafe fn activate_persistent(self: Box) { - set_tls_ptr((&*self) as *const Tls as _); + // FIXME: Needs safety information. See entry.S for `set_tls_ptr` definition. + unsafe { set_tls_ptr((&*self) as *const Tls as _) }; mem::forget(self); } unsafe fn current<'a>() -> &'a Tls { - &*(get_tls_ptr() as *const Tls) + // FIXME: Needs safety information. See entry.S for `set_tls_ptr` definition. + unsafe { &*(get_tls_ptr() as *const Tls) } } pub fn create(dtor: Option) -> Key { diff --git a/library/std/src/sys/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/sgx/abi/usercalls/alloc.rs index 76a9b427b39c6..9fdb1b4584479 100644 --- a/library/std/src/sys/sgx/abi/usercalls/alloc.rs +++ b/library/std/src/sys/sgx/abi/usercalls/alloc.rs @@ -89,9 +89,12 @@ pub unsafe trait UserSafe { /// * the pointed-to range is not in user memory. unsafe fn from_raw_sized(ptr: *mut u8, size: usize) -> NonNull { assert!(ptr.wrapping_add(size) >= ptr); - let ret = Self::from_raw_sized_unchecked(ptr, size); - Self::check_ptr(ret); - NonNull::new_unchecked(ret as _) + // SAFETY: The caller has guaranteed the pointer is valid + let ret = unsafe { Self::from_raw_sized_unchecked(ptr, size) }; + unsafe { + Self::check_ptr(ret); + NonNull::new_unchecked(ret as _) + } } /// Checks if a pointer may point to `Self` in user memory. @@ -112,7 +115,7 @@ pub unsafe trait UserSafe { let is_aligned = |p| -> bool { 0 == (p as usize) & (Self::align_of() - 1) }; assert!(is_aligned(ptr as *const u8)); - assert!(is_user_range(ptr as _, mem::size_of_val(&*ptr))); + assert!(is_user_range(ptr as _, mem::size_of_val(unsafe { &*ptr }))); assert!(!ptr.is_null()); } } @@ -135,11 +138,23 @@ unsafe impl UserSafe for [T] { mem::align_of::() } + /// # Safety + /// Behavior is undefined if any of these conditions are violated: + /// * `ptr` must be [valid] for writes of `size` many bytes, and it must be + /// properly aligned. + /// + /// [valid]: core::ptr#safety + /// # Panics + /// + /// This function panics if: + /// + /// * the element size is not a factor of the size unsafe fn from_raw_sized_unchecked(ptr: *mut u8, size: usize) -> *mut Self { let elem_size = mem::size_of::(); assert_eq!(size % elem_size, 0); let len = size / elem_size; - slice::from_raw_parts_mut(ptr as _, len) + // SAFETY: The caller must uphold the safety contract for `from_raw_sized_unchecked` + unsafe { slice::from_raw_parts_mut(ptr as _, len) } } } @@ -170,13 +185,15 @@ trait NewUserRef { impl NewUserRef<*mut T> for NonNull> { unsafe fn new_userref(v: *mut T) -> Self { - NonNull::new_unchecked(v as _) + // SAFETY: The caller has guaranteed the pointer is valid + unsafe { NonNull::new_unchecked(v as _) } } } impl NewUserRef> for NonNull> { unsafe fn new_userref(v: NonNull) -> Self { - NonNull::new_userref(v.as_ptr()) + // SAFETY: The caller has guaranteed the pointer is valid + unsafe { NonNull::new_userref(v.as_ptr()) } } } @@ -231,8 +248,9 @@ where /// * The pointer is null /// * The pointed-to range is not in user memory pub unsafe fn from_raw(ptr: *mut T) -> Self { - T::check_ptr(ptr); - User(NonNull::new_userref(ptr)) + // SAFETY: the caller must uphold the safety contract for `from_raw`. + unsafe { T::check_ptr(ptr) }; + User(unsafe { NonNull::new_userref(ptr) }) } /// Converts this value into a raw pointer. The value will no longer be @@ -280,7 +298,9 @@ where /// * The pointed-to range does not fit in the address space /// * The pointed-to range is not in user memory pub unsafe fn from_raw_parts(ptr: *mut T, len: usize) -> Self { - User(NonNull::new_userref(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::()))) + User(unsafe { + NonNull::new_userref(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::())) + }) } } @@ -301,8 +321,9 @@ where /// * The pointer is null /// * The pointed-to range is not in user memory pub unsafe fn from_ptr<'a>(ptr: *const T) -> &'a Self { - T::check_ptr(ptr); - &*(ptr as *const Self) + // SAFETY: The caller must uphold the safety contract for `from_ptr`. + unsafe { T::check_ptr(ptr) }; + unsafe { &*(ptr as *const Self) } } /// Creates a `&mut UserRef<[T]>` from a raw pointer. See the struct @@ -318,8 +339,9 @@ where /// * The pointer is null /// * The pointed-to range is not in user memory pub unsafe fn from_mut_ptr<'a>(ptr: *mut T) -> &'a mut Self { - T::check_ptr(ptr); - &mut *(ptr as *mut Self) + // SAFETY: The caller must uphold the safety contract for `from_mut_ptr`. + unsafe { T::check_ptr(ptr) }; + unsafe { &mut *(ptr as *mut Self) } } /// Copies `val` into user memory. @@ -394,7 +416,10 @@ where /// * The pointed-to range does not fit in the address space /// * The pointed-to range is not in user memory pub unsafe fn from_raw_parts<'a>(ptr: *const T, len: usize) -> &'a Self { - &*(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::()).as_ptr() as *const Self) + // SAFETY: The caller must uphold the safety contract for `from_raw_parts`. + unsafe { + &*(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::()).as_ptr() as *const Self) + } } /// Creates a `&mut UserRef<[T]>` from a raw thin pointer and a slice length. @@ -412,7 +437,10 @@ where /// * The pointed-to range does not fit in the address space /// * The pointed-to range is not in user memory pub unsafe fn from_raw_parts_mut<'a>(ptr: *mut T, len: usize) -> &'a mut Self { - &mut *(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::()).as_ptr() as *mut Self) + // SAFETY: The caller must uphold the safety contract for `from_raw_parts_mut`. + unsafe { + &mut *(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::()).as_ptr() as *mut Self) + } } /// Obtain a raw pointer to the first element of this user slice. @@ -437,13 +465,12 @@ where /// This function panics if the destination doesn't have the same size as /// the source. This can happen for dynamically-sized types such as slices. pub fn copy_to_enclave_vec(&self, dest: &mut Vec) { - unsafe { - if let Some(missing) = self.len().checked_sub(dest.capacity()) { - dest.reserve(missing) - } - dest.set_len(self.len()); - self.copy_to_enclave(&mut dest[..]); + if let Some(missing) = self.len().checked_sub(dest.capacity()) { + dest.reserve(missing) } + // SAFETY: We reserve enough space above. + unsafe { dest.set_len(self.len()) }; + self.copy_to_enclave(&mut dest[..]); } /// Copies the value from user memory into a vector in enclave memory. diff --git a/library/std/src/sys/sgx/abi/usercalls/mod.rs b/library/std/src/sys/sgx/abi/usercalls/mod.rs index 73f1b951e7430..a6a659df291fc 100644 --- a/library/std/src/sys/sgx/abi/usercalls/mod.rs +++ b/library/std/src/sys/sgx/abi/usercalls/mod.rs @@ -140,7 +140,8 @@ pub fn connect_stream(addr: &str) -> IoResult<(Fd, String, String)> { /// Usercall `launch_thread`. See the ABI documentation for more information. #[unstable(feature = "sgx_platform", issue = "56975")] pub unsafe fn launch_thread() -> IoResult<()> { - raw::launch_thread().from_sgx_result() + // SAFETY: The caller must uphold the safety contract for `launch_thread`. + unsafe { raw::launch_thread().from_sgx_result() } } /// Usercall `exit`. See the ABI documentation for more information. diff --git a/library/std/src/sys/sgx/abi/usercalls/raw.rs b/library/std/src/sys/sgx/abi/usercalls/raw.rs index e0ebf860618c8..b0e6a6aaed7b9 100644 --- a/library/std/src/sys/sgx/abi/usercalls/raw.rs +++ b/library/std/src/sys/sgx/abi/usercalls/raw.rs @@ -33,7 +33,7 @@ pub unsafe fn do_usercall( p4: u64, abort: bool, ) -> (u64, u64) { - let UsercallReturn(a, b) = usercall(nr, p1, p2, abort as _, p3, p4); + let UsercallReturn(a, b) = unsafe { usercall(nr, p1, p2, abort as _, p3, p4) }; (a, b) } @@ -175,14 +175,14 @@ macro_rules! enclave_usercalls_internal_define_usercalls { #[unstable(feature = "sgx_platform", issue = "56975")] #[inline(always)] pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3, $n4: $t4) -> $r { - ReturnValue::from_registers(stringify!($f), do_usercall( - rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)), - RegisterArgument::into_register($n1), - RegisterArgument::into_register($n2), - RegisterArgument::into_register($n3), - RegisterArgument::into_register($n4), - return_type_is_abort!($r) - )) + ReturnValue::from_registers(stringify!($f), unsafe { do_usercall( + rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)), + RegisterArgument::into_register($n1), + RegisterArgument::into_register($n2), + RegisterArgument::into_register($n3), + RegisterArgument::into_register($n4), + return_type_is_abort!($r) + ) }) } ); (def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty, $n3:ident: $t3:ty) -> $r:tt) => ( @@ -191,14 +191,14 @@ macro_rules! enclave_usercalls_internal_define_usercalls { #[unstable(feature = "sgx_platform", issue = "56975")] #[inline(always)] pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3) -> $r { - ReturnValue::from_registers(stringify!($f), do_usercall( - rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)), - RegisterArgument::into_register($n1), - RegisterArgument::into_register($n2), - RegisterArgument::into_register($n3), - 0, - return_type_is_abort!($r) - )) + ReturnValue::from_registers(stringify!($f), unsafe { do_usercall( + rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)), + RegisterArgument::into_register($n1), + RegisterArgument::into_register($n2), + RegisterArgument::into_register($n3), + 0, + return_type_is_abort!($r) + ) }) } ); (def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty) -> $r:tt) => ( @@ -207,13 +207,13 @@ macro_rules! enclave_usercalls_internal_define_usercalls { #[unstable(feature = "sgx_platform", issue = "56975")] #[inline(always)] pub unsafe fn $f($n1: $t1, $n2: $t2) -> $r { - ReturnValue::from_registers(stringify!($f), do_usercall( - rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)), - RegisterArgument::into_register($n1), - RegisterArgument::into_register($n2), - 0,0, - return_type_is_abort!($r) - )) + ReturnValue::from_registers(stringify!($f), unsafe { do_usercall( + rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)), + RegisterArgument::into_register($n1), + RegisterArgument::into_register($n2), + 0,0, + return_type_is_abort!($r) + ) }) } ); (def fn $f:ident($n1:ident: $t1:ty) -> $r:tt) => ( @@ -222,12 +222,12 @@ macro_rules! enclave_usercalls_internal_define_usercalls { #[unstable(feature = "sgx_platform", issue = "56975")] #[inline(always)] pub unsafe fn $f($n1: $t1) -> $r { - ReturnValue::from_registers(stringify!($f), do_usercall( - rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)), - RegisterArgument::into_register($n1), - 0,0,0, - return_type_is_abort!($r) - )) + ReturnValue::from_registers(stringify!($f), unsafe { do_usercall( + rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)), + RegisterArgument::into_register($n1), + 0,0,0, + return_type_is_abort!($r) + ) }) } ); (def fn $f:ident() -> $r:tt) => ( @@ -236,11 +236,11 @@ macro_rules! enclave_usercalls_internal_define_usercalls { #[unstable(feature = "sgx_platform", issue = "56975")] #[inline(always)] pub unsafe fn $f() -> $r { - ReturnValue::from_registers(stringify!($f), do_usercall( - rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)), - 0,0,0,0, - return_type_is_abort!($r) - )) + ReturnValue::from_registers(stringify!($f), unsafe { do_usercall( + rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)), + 0,0,0,0, + return_type_is_abort!($r) + ) }) } ); (def fn $f:ident($($n:ident: $t:ty),*)) => ( diff --git a/library/std/src/sys/sgx/alloc.rs b/library/std/src/sys/sgx/alloc.rs index 40daec758a9fc..4559ea7cd2540 100644 --- a/library/std/src/sys/sgx/alloc.rs +++ b/library/std/src/sys/sgx/alloc.rs @@ -4,6 +4,10 @@ use super::waitqueue::SpinMutex; // Using a SpinMutex because we never want to exit the enclave waiting for the // allocator. +// +// The current allocator here is the `dlmalloc` crate which we've got included +// in the rust-lang/rust repository as a submodule. The crate is a port of +// dlmalloc.c from C to Rust. #[cfg_attr(test, linkage = "available_externally")] #[export_name = "_ZN16__rust_internals3std3sys3sgx5alloc8DLMALLOCE"] static DLMALLOC: SpinMutex = SpinMutex::new(dlmalloc::DLMALLOC_INIT); @@ -12,22 +16,26 @@ static DLMALLOC: SpinMutex = SpinMutex::new(dlmalloc::DLMALL unsafe impl GlobalAlloc for System { #[inline] unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - DLMALLOC.lock().malloc(layout.size(), layout.align()) + // SAFETY: the caller must uphold the safety contract for `malloc` + unsafe { DLMALLOC.lock().malloc(layout.size(), layout.align()) } } #[inline] unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { - DLMALLOC.lock().calloc(layout.size(), layout.align()) + // SAFETY: the caller must uphold the safety contract for `malloc` + unsafe { DLMALLOC.lock().calloc(layout.size(), layout.align()) } } #[inline] unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { - DLMALLOC.lock().free(ptr, layout.size(), layout.align()) + // SAFETY: the caller must uphold the safety contract for `malloc` + unsafe { DLMALLOC.lock().free(ptr, layout.size(), layout.align()) } } #[inline] unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { - DLMALLOC.lock().realloc(ptr, layout.size(), layout.align(), new_size) + // SAFETY: the caller must uphold the safety contract for `malloc` + unsafe { DLMALLOC.lock().realloc(ptr, layout.size(), layout.align(), new_size) } } } @@ -36,11 +44,11 @@ unsafe impl GlobalAlloc for System { #[cfg(not(test))] #[no_mangle] pub unsafe extern "C" fn __rust_c_alloc(size: usize, align: usize) -> *mut u8 { - crate::alloc::alloc(Layout::from_size_align_unchecked(size, align)) + unsafe { crate::alloc::alloc(Layout::from_size_align_unchecked(size, align)) } } #[cfg(not(test))] #[no_mangle] pub unsafe extern "C" fn __rust_c_dealloc(ptr: *mut u8, size: usize, align: usize) { - crate::alloc::dealloc(ptr, Layout::from_size_align_unchecked(size, align)) + unsafe { crate::alloc::dealloc(ptr, Layout::from_size_align_unchecked(size, align)) } } diff --git a/library/std/src/sys/sgx/args.rs b/library/std/src/sys/sgx/args.rs index 5a53695a8466b..2d2e692ec7d35 100644 --- a/library/std/src/sys/sgx/args.rs +++ b/library/std/src/sys/sgx/args.rs @@ -13,7 +13,7 @@ type ArgsStore = Vec; #[cfg_attr(test, allow(dead_code))] pub unsafe fn init(argc: isize, argv: *const *const u8) { if argc != 0 { - let args = alloc::User::<[ByteBuffer]>::from_raw_parts(argv as _, argc as _); + let args = unsafe { alloc::User::<[ByteBuffer]>::from_raw_parts(argv as _, argc as _) }; let args = args .iter() .map(|a| OsString::from_inner(Buf { inner: a.copy_user_buffer() })) diff --git a/library/std/src/sys/sgx/condvar.rs b/library/std/src/sys/sgx/condvar.rs index dfe22e6a1b375..55ac052d97508 100644 --- a/library/std/src/sys/sgx/condvar.rs +++ b/library/std/src/sys/sgx/condvar.rs @@ -29,13 +29,13 @@ impl Condvar { pub unsafe fn wait(&self, mutex: &Mutex) { let guard = self.inner.lock(); - WaitQueue::wait(guard, || mutex.unlock()); - mutex.lock() + WaitQueue::wait(guard, || unsafe { mutex.unlock() }); + unsafe { mutex.lock() } } pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { - let success = WaitQueue::wait_timeout(&self.inner, dur, || mutex.unlock()); - mutex.lock(); + let success = WaitQueue::wait_timeout(&self.inner, dur, || unsafe { mutex.unlock() }); + unsafe { mutex.lock() }; success } diff --git a/library/std/src/sys/sgx/mod.rs b/library/std/src/sys/sgx/mod.rs index 1abd91e75e8c4..b10bed621dbad 100644 --- a/library/std/src/sys/sgx/mod.rs +++ b/library/std/src/sys/sgx/mod.rs @@ -2,6 +2,7 @@ //! //! This module contains the facade (aka platform-specific) implementations of //! OS level functionality for Fortanix SGX. +#![deny(unsafe_op_in_unsafe_fn)] use crate::io::ErrorKind; use crate::os::raw::c_char; @@ -121,9 +122,9 @@ pub enum Void {} pub unsafe fn strlen(mut s: *const c_char) -> usize { let mut n = 0; - while *s != 0 { + while unsafe { *s } != 0 { n += 1; - s = s.offset(1); + s = unsafe { s.offset(1) }; } return n; } diff --git a/library/std/src/sys/sgx/rwlock.rs b/library/std/src/sys/sgx/rwlock.rs index 3bf2a7d8fb46c..0c96e3fcddcdf 100644 --- a/library/std/src/sys/sgx/rwlock.rs +++ b/library/std/src/sys/sgx/rwlock.rs @@ -14,9 +14,12 @@ pub struct RWLock { } // Check at compile time that RWLock size matches C definition (see test_c_rwlock_initializer below) +// +// # Safety +// Never called, as it is a compile time check. #[allow(dead_code)] unsafe fn rw_lock_size_assert(r: RWLock) { - mem::transmute::(r); + unsafe { mem::transmute::(r) }; } impl RWLock { @@ -112,7 +115,7 @@ impl RWLock { pub unsafe fn read_unlock(&self) { let rguard = self.readers.lock(); let wguard = self.writer.lock(); - self.__read_unlock(rguard, wguard); + unsafe { self.__read_unlock(rguard, wguard) }; } #[inline] @@ -148,7 +151,7 @@ impl RWLock { pub unsafe fn write_unlock(&self) { let rguard = self.readers.lock(); let wguard = self.writer.lock(); - self.__write_unlock(rguard, wguard); + unsafe { self.__write_unlock(rguard, wguard) }; } // only used by __rust_rwlock_unlock below @@ -158,9 +161,9 @@ impl RWLock { let rguard = self.readers.lock(); let wguard = self.writer.lock(); if *wguard.lock_var() == true { - self.__write_unlock(rguard, wguard); + unsafe { self.__write_unlock(rguard, wguard) }; } else { - self.__read_unlock(rguard, wguard); + unsafe { self.__read_unlock(rguard, wguard) }; } } @@ -179,7 +182,7 @@ pub unsafe extern "C" fn __rust_rwlock_rdlock(p: *mut RWLock) -> i32 { if p.is_null() { return EINVAL; } - (*p).read(); + unsafe { (*p).read() }; return 0; } @@ -189,7 +192,7 @@ pub unsafe extern "C" fn __rust_rwlock_wrlock(p: *mut RWLock) -> i32 { if p.is_null() { return EINVAL; } - (*p).write(); + unsafe { (*p).write() }; return 0; } #[cfg(not(test))] @@ -198,6 +201,6 @@ pub unsafe extern "C" fn __rust_rwlock_unlock(p: *mut RWLock) -> i32 { if p.is_null() { return EINVAL; } - (*p).unlock(); + unsafe { (*p).unlock() }; return 0; } diff --git a/library/std/src/sys/sgx/stdio.rs b/library/std/src/sys/sgx/stdio.rs index 49f44f9f498ac..548e28a43d646 100644 --- a/library/std/src/sys/sgx/stdio.rs +++ b/library/std/src/sys/sgx/stdio.rs @@ -81,7 +81,7 @@ pub unsafe extern "C" fn __rust_print_err(m: *mut u8, s: i32) { if s < 0 { return; } - let buf = slice::from_raw_parts(m as *const u8, s as _); + let buf = unsafe { slice::from_raw_parts(m as *const u8, s as _) }; if let Ok(s) = str::from_utf8(&buf[..buf.iter().position(|&b| b == 0).unwrap_or(buf.len())]) { eprint!("{}", s); } diff --git a/library/std/src/sys/sgx/thread.rs b/library/std/src/sys/sgx/thread.rs index 5895f70436efa..55ef460cc90c5 100644 --- a/library/std/src/sys/sgx/thread.rs +++ b/library/std/src/sys/sgx/thread.rs @@ -51,7 +51,7 @@ impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements pub unsafe fn new(_stack: usize, p: Box) -> io::Result { let mut queue_lock = task_queue::lock(); - usercalls::launch_thread()?; + unsafe { usercalls::launch_thread()? }; let (task, handle) = task_queue::Task::new(p); queue_lock.push(task); Ok(Thread(handle)) diff --git a/library/std/src/sys/sgx/waitqueue/unsafe_list.rs b/library/std/src/sys/sgx/waitqueue/unsafe_list.rs index 7a2465427396d..0834d2593fc32 100644 --- a/library/std/src/sys/sgx/waitqueue/unsafe_list.rs +++ b/library/std/src/sys/sgx/waitqueue/unsafe_list.rs @@ -30,31 +30,34 @@ impl UnsafeList { unsafe { UnsafeList { head_tail: NonNull::new_unchecked(1 as _), head_tail_entry: None } } } + /// # Safety unsafe fn init(&mut self) { if self.head_tail_entry.is_none() { self.head_tail_entry = Some(UnsafeListEntry::dummy()); - self.head_tail = NonNull::new_unchecked(self.head_tail_entry.as_mut().unwrap()); - self.head_tail.as_mut().next = self.head_tail; - self.head_tail.as_mut().prev = self.head_tail; + // SAFETY: `head_tail_entry` must be non-null, which it is because we assign it above. + self.head_tail = + unsafe { NonNull::new_unchecked(self.head_tail_entry.as_mut().unwrap()) }; + // SAFETY: `self.head_tail` must meet all requirements for a mutable reference. + unsafe { self.head_tail.as_mut() }.next = self.head_tail; + unsafe { self.head_tail.as_mut() }.prev = self.head_tail; } } pub fn is_empty(&self) -> bool { - unsafe { - if self.head_tail_entry.is_some() { - let first = self.head_tail.as_ref().next; - if first == self.head_tail { - // ,-------> /---------\ next ---, - // | |head_tail| | - // `--- prev \---------/ <-------` - rtassert!(self.head_tail.as_ref().prev == first); - true - } else { - false - } - } else { + if self.head_tail_entry.is_some() { + let first = unsafe { self.head_tail.as_ref() }.next; + if first == self.head_tail { + // ,-------> /---------\ next ---, + // | |head_tail| | + // `--- prev \---------/ <-------` + // SAFETY: `self.head_tail` must meet all requirements for a reference. + unsafe { rtassert!(self.head_tail.as_ref().prev == first) }; true + } else { + false } + } else { + true } } @@ -67,7 +70,7 @@ impl UnsafeList { /// care must be taken in the caller of `push` to ensure unwinding does /// not destroy the stack frame containing the entry. pub unsafe fn push<'a>(&mut self, entry: &'a mut UnsafeListEntry) -> &'a T { - self.init(); + unsafe { self.init() }; // BEFORE: // /---------\ next ---> /---------\ @@ -78,13 +81,15 @@ impl UnsafeList { // /---------\ next ---> /-----\ next ---> /---------\ // ... |prev_tail| |entry| |head_tail| ... // \---------/ <--- prev \-----/ <--- prev \---------/ - let mut entry = NonNull::new_unchecked(entry); - let mut prev_tail = mem::replace(&mut self.head_tail.as_mut().prev, entry); - entry.as_mut().prev = prev_tail; - entry.as_mut().next = self.head_tail; - prev_tail.as_mut().next = entry; + let mut entry = unsafe { NonNull::new_unchecked(entry) }; + let mut prev_tail = mem::replace(&mut unsafe { self.head_tail.as_mut() }.prev, entry); + // SAFETY: `entry` must meet all requirements for a mutable reference. + unsafe { entry.as_mut() }.prev = prev_tail; + unsafe { entry.as_mut() }.next = self.head_tail; + // SAFETY: `prev_tail` must meet all requirements for a mutable reference. + unsafe { prev_tail.as_mut() }.next = entry; // unwrap ok: always `Some` on non-dummy entries - (*entry.as_ptr()).value.as_ref().unwrap() + unsafe { (*entry.as_ptr()).value.as_ref() }.unwrap() } /// Pops an entry from the front of the list. @@ -94,7 +99,7 @@ impl UnsafeList { /// The caller must make sure to synchronize ending the borrow of the /// return value and deallocation of the containing entry. pub unsafe fn pop<'a>(&mut self) -> Option<&'a T> { - self.init(); + unsafe { self.init() }; if self.is_empty() { None @@ -108,14 +113,14 @@ impl UnsafeList { // /---------\ next ---> /------\ // ... |head_tail| |second| ... // \---------/ <--- prev \------/ - let mut first = self.head_tail.as_mut().next; - let mut second = first.as_mut().next; - self.head_tail.as_mut().next = second; - second.as_mut().prev = self.head_tail; - first.as_mut().next = NonNull::dangling(); - first.as_mut().prev = NonNull::dangling(); + let mut first = unsafe { self.head_tail.as_mut() }.next; + let mut second = unsafe { first.as_mut() }.next; + unsafe { self.head_tail.as_mut() }.next = second; + unsafe { second.as_mut() }.prev = self.head_tail; + unsafe { first.as_mut() }.next = NonNull::dangling(); + unsafe { first.as_mut() }.prev = NonNull::dangling(); // unwrap ok: always `Some` on non-dummy entries - Some((*first.as_ptr()).value.as_ref().unwrap()) + Some(unsafe { (*first.as_ptr()).value.as_ref() }.unwrap()) } } @@ -138,8 +143,9 @@ impl UnsafeList { // \----/ <--- prev \----/ let mut prev = entry.prev; let mut next = entry.next; - prev.as_mut().next = next; - next.as_mut().prev = prev; + // SAFETY: `prev` and `next` must meet all requirements for a mutable reference.entry + unsafe { prev.as_mut() }.next = next; + unsafe { next.as_mut() }.prev = prev; entry.next = NonNull::dangling(); entry.prev = NonNull::dangling(); } diff --git a/library/std/src/sys/sgx/waitqueue/unsafe_list/tests.rs b/library/std/src/sys/sgx/waitqueue/unsafe_list/tests.rs index 1f031ed1959cf..c653dee17bc36 100644 --- a/library/std/src/sys/sgx/waitqueue/unsafe_list/tests.rs +++ b/library/std/src/sys/sgx/waitqueue/unsafe_list/tests.rs @@ -1,8 +1,10 @@ use super::*; use crate::cell::Cell; +/// # Safety +/// List must be valid. unsafe fn assert_empty(list: &mut UnsafeList) { - assert!(list.pop().is_none(), "assertion failed: list is not empty"); + assert!(unsafe { list.pop() }.is_none(), "assertion failed: list is not empty"); } #[test]