`#[deny(unsafe_op_in_unsafe_fn)]` in sys/sgx

Run `./x.py` fmt

Add reference link

Fix reference link

Apply review suggestions.
This commit is contained in:
Caduser2020 2020-09-29 15:27:56 -05:00
parent 4d52dc4790
commit 1fb0a1d501
14 changed files with 170 additions and 119 deletions

View File

@ -45,7 +45,7 @@ unsafe extern "C" fn tcs_init(secondary: bool) {
// We need to wait until the initialization is done. // We need to wait until the initialization is done.
BUSY => { BUSY => {
while RELOC_STATE.load(Ordering::Acquire) == BUSY { while RELOC_STATE.load(Ordering::Acquire) == BUSY {
core::arch::x86_64::_mm_pause() core::hint::spin_loop();
} }
} }
// Initialization is done. // Initialization is done.

View File

@ -87,18 +87,21 @@ impl Tls {
} }
pub unsafe fn activate(&self) -> ActiveTls<'_> { 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 } ActiveTls { tls: self }
} }
#[allow(unused)] #[allow(unused)]
pub unsafe fn activate_persistent(self: Box<Self>) { pub unsafe fn activate_persistent(self: Box<Self>) {
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); mem::forget(self);
} }
unsafe fn current<'a>() -> &'a Tls { 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<unsafe extern "C" fn(*mut u8)>) -> Key { pub fn create(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key {

View File

@ -89,9 +89,12 @@ pub unsafe trait UserSafe {
/// * the pointed-to range is not in user memory. /// * the pointed-to range is not in user memory.
unsafe fn from_raw_sized(ptr: *mut u8, size: usize) -> NonNull<Self> { unsafe fn from_raw_sized(ptr: *mut u8, size: usize) -> NonNull<Self> {
assert!(ptr.wrapping_add(size) >= ptr); assert!(ptr.wrapping_add(size) >= ptr);
let ret = Self::from_raw_sized_unchecked(ptr, size); // SAFETY: The caller has guaranteed the pointer is valid
Self::check_ptr(ret); let ret = unsafe { Self::from_raw_sized_unchecked(ptr, size) };
NonNull::new_unchecked(ret as _) unsafe {
Self::check_ptr(ret);
NonNull::new_unchecked(ret as _)
}
} }
/// Checks if a pointer may point to `Self` in user memory. /// 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) }; let is_aligned = |p| -> bool { 0 == (p as usize) & (Self::align_of() - 1) };
assert!(is_aligned(ptr as *const u8)); 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()); assert!(!ptr.is_null());
} }
} }
@ -135,11 +138,23 @@ unsafe impl<T: UserSafeSized> UserSafe for [T] {
mem::align_of::<T>() mem::align_of::<T>()
} }
/// # 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 { unsafe fn from_raw_sized_unchecked(ptr: *mut u8, size: usize) -> *mut Self {
let elem_size = mem::size_of::<T>(); let elem_size = mem::size_of::<T>();
assert_eq!(size % elem_size, 0); assert_eq!(size % elem_size, 0);
let len = size / elem_size; 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<T: ?Sized> {
impl<T: ?Sized> NewUserRef<*mut T> for NonNull<UserRef<T>> { impl<T: ?Sized> NewUserRef<*mut T> for NonNull<UserRef<T>> {
unsafe fn new_userref(v: *mut T) -> Self { 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<T: ?Sized> NewUserRef<NonNull<T>> for NonNull<UserRef<T>> { impl<T: ?Sized> NewUserRef<NonNull<T>> for NonNull<UserRef<T>> {
unsafe fn new_userref(v: NonNull<T>) -> Self { unsafe fn new_userref(v: NonNull<T>) -> 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 pointer is null
/// * The pointed-to range is not in user memory /// * The pointed-to range is not in user memory
pub unsafe fn from_raw(ptr: *mut T) -> Self { pub unsafe fn from_raw(ptr: *mut T) -> Self {
T::check_ptr(ptr); // SAFETY: the caller must uphold the safety contract for `from_raw`.
User(NonNull::new_userref(ptr)) unsafe { T::check_ptr(ptr) };
User(unsafe { NonNull::new_userref(ptr) })
} }
/// Converts this value into a raw pointer. The value will no longer be /// 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 does not fit in the address space
/// * The pointed-to range is not in user memory /// * The pointed-to range is not in user memory
pub unsafe fn from_raw_parts(ptr: *mut T, len: usize) -> Self { 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::<T>()))) User(unsafe {
NonNull::new_userref(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()))
})
} }
} }
@ -301,8 +321,9 @@ where
/// * The pointer is null /// * The pointer is null
/// * The pointed-to range is not in user memory /// * The pointed-to range is not in user memory
pub unsafe fn from_ptr<'a>(ptr: *const T) -> &'a Self { pub unsafe fn from_ptr<'a>(ptr: *const T) -> &'a Self {
T::check_ptr(ptr); // SAFETY: The caller must uphold the safety contract for `from_ptr`.
&*(ptr as *const Self) unsafe { T::check_ptr(ptr) };
unsafe { &*(ptr as *const Self) }
} }
/// Creates a `&mut UserRef<[T]>` from a raw pointer. See the struct /// Creates a `&mut UserRef<[T]>` from a raw pointer. See the struct
@ -318,8 +339,9 @@ where
/// * The pointer is null /// * The pointer is null
/// * The pointed-to range is not in user memory /// * The pointed-to range is not in user memory
pub unsafe fn from_mut_ptr<'a>(ptr: *mut T) -> &'a mut Self { pub unsafe fn from_mut_ptr<'a>(ptr: *mut T) -> &'a mut Self {
T::check_ptr(ptr); // SAFETY: The caller must uphold the safety contract for `from_mut_ptr`.
&mut *(ptr as *mut Self) unsafe { T::check_ptr(ptr) };
unsafe { &mut *(ptr as *mut Self) }
} }
/// Copies `val` into user memory. /// 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 does not fit in the address space
/// * The pointed-to range is not in user memory /// * The pointed-to range is not in user memory
pub unsafe fn from_raw_parts<'a>(ptr: *const T, len: usize) -> &'a Self { pub unsafe fn from_raw_parts<'a>(ptr: *const T, len: usize) -> &'a Self {
&*(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()).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::<T>()).as_ptr() as *const Self)
}
} }
/// Creates a `&mut UserRef<[T]>` from a raw thin pointer and a slice length. /// 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 does not fit in the address space
/// * The pointed-to range is not in user memory /// * 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 { 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::<T>()).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::<T>()).as_ptr() as *mut Self)
}
} }
/// Obtain a raw pointer to the first element of this user slice. /// 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 /// 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. /// the source. This can happen for dynamically-sized types such as slices.
pub fn copy_to_enclave_vec(&self, dest: &mut Vec<T>) { pub fn copy_to_enclave_vec(&self, dest: &mut Vec<T>) {
unsafe { if let Some(missing) = self.len().checked_sub(dest.capacity()) {
if let Some(missing) = self.len().checked_sub(dest.capacity()) { dest.reserve(missing)
dest.reserve(missing)
}
dest.set_len(self.len());
self.copy_to_enclave(&mut dest[..]);
} }
// 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. /// Copies the value from user memory into a vector in enclave memory.

View File

@ -140,7 +140,8 @@ pub fn connect_stream(addr: &str) -> IoResult<(Fd, String, String)> {
/// Usercall `launch_thread`. See the ABI documentation for more information. /// Usercall `launch_thread`. See the ABI documentation for more information.
#[unstable(feature = "sgx_platform", issue = "56975")] #[unstable(feature = "sgx_platform", issue = "56975")]
pub unsafe fn launch_thread() -> IoResult<()> { 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. /// Usercall `exit`. See the ABI documentation for more information.

View File

@ -33,7 +33,7 @@ pub unsafe fn do_usercall(
p4: u64, p4: u64,
abort: bool, abort: bool,
) -> (u64, u64) { ) -> (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) (a, b)
} }
@ -175,14 +175,14 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
#[unstable(feature = "sgx_platform", issue = "56975")] #[unstable(feature = "sgx_platform", issue = "56975")]
#[inline(always)] #[inline(always)]
pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3, $n4: $t4) -> $r { pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3, $n4: $t4) -> $r {
ReturnValue::from_registers(stringify!($f), do_usercall( ReturnValue::from_registers(stringify!($f), unsafe { do_usercall(
rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)), rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
RegisterArgument::into_register($n1), RegisterArgument::into_register($n1),
RegisterArgument::into_register($n2), RegisterArgument::into_register($n2),
RegisterArgument::into_register($n3), RegisterArgument::into_register($n3),
RegisterArgument::into_register($n4), RegisterArgument::into_register($n4),
return_type_is_abort!($r) return_type_is_abort!($r)
)) ) })
} }
); );
(def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty, $n3:ident: $t3:ty) -> $r:tt) => ( (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")] #[unstable(feature = "sgx_platform", issue = "56975")]
#[inline(always)] #[inline(always)]
pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3) -> $r { pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3) -> $r {
ReturnValue::from_registers(stringify!($f), do_usercall( ReturnValue::from_registers(stringify!($f), unsafe { do_usercall(
rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)), rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
RegisterArgument::into_register($n1), RegisterArgument::into_register($n1),
RegisterArgument::into_register($n2), RegisterArgument::into_register($n2),
RegisterArgument::into_register($n3), RegisterArgument::into_register($n3),
0, 0,
return_type_is_abort!($r) return_type_is_abort!($r)
)) ) })
} }
); );
(def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty) -> $r:tt) => ( (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")] #[unstable(feature = "sgx_platform", issue = "56975")]
#[inline(always)] #[inline(always)]
pub unsafe fn $f($n1: $t1, $n2: $t2) -> $r { pub unsafe fn $f($n1: $t1, $n2: $t2) -> $r {
ReturnValue::from_registers(stringify!($f), do_usercall( ReturnValue::from_registers(stringify!($f), unsafe { do_usercall(
rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)), rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
RegisterArgument::into_register($n1), RegisterArgument::into_register($n1),
RegisterArgument::into_register($n2), RegisterArgument::into_register($n2),
0,0, 0,0,
return_type_is_abort!($r) return_type_is_abort!($r)
)) ) })
} }
); );
(def fn $f:ident($n1:ident: $t1:ty) -> $r:tt) => ( (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")] #[unstable(feature = "sgx_platform", issue = "56975")]
#[inline(always)] #[inline(always)]
pub unsafe fn $f($n1: $t1) -> $r { pub unsafe fn $f($n1: $t1) -> $r {
ReturnValue::from_registers(stringify!($f), do_usercall( ReturnValue::from_registers(stringify!($f), unsafe { do_usercall(
rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)), rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
RegisterArgument::into_register($n1), RegisterArgument::into_register($n1),
0,0,0, 0,0,0,
return_type_is_abort!($r) return_type_is_abort!($r)
)) ) })
} }
); );
(def fn $f:ident() -> $r:tt) => ( (def fn $f:ident() -> $r:tt) => (
@ -236,11 +236,11 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
#[unstable(feature = "sgx_platform", issue = "56975")] #[unstable(feature = "sgx_platform", issue = "56975")]
#[inline(always)] #[inline(always)]
pub unsafe fn $f() -> $r { pub unsafe fn $f() -> $r {
ReturnValue::from_registers(stringify!($f), do_usercall( ReturnValue::from_registers(stringify!($f), unsafe { do_usercall(
rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)), rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
0,0,0,0, 0,0,0,0,
return_type_is_abort!($r) return_type_is_abort!($r)
)) ) })
} }
); );
(def fn $f:ident($($n:ident: $t:ty),*)) => ( (def fn $f:ident($($n:ident: $t:ty),*)) => (

View File

@ -4,6 +4,10 @@ use super::waitqueue::SpinMutex;
// Using a SpinMutex because we never want to exit the enclave waiting for the // Using a SpinMutex because we never want to exit the enclave waiting for the
// allocator. // 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")] #[cfg_attr(test, linkage = "available_externally")]
#[export_name = "_ZN16__rust_internals3std3sys3sgx5alloc8DLMALLOCE"] #[export_name = "_ZN16__rust_internals3std3sys3sgx5alloc8DLMALLOCE"]
static DLMALLOC: SpinMutex<dlmalloc::Dlmalloc> = SpinMutex::new(dlmalloc::DLMALLOC_INIT); static DLMALLOC: SpinMutex<dlmalloc::Dlmalloc> = SpinMutex::new(dlmalloc::DLMALLOC_INIT);
@ -12,22 +16,26 @@ static DLMALLOC: SpinMutex<dlmalloc::Dlmalloc> = SpinMutex::new(dlmalloc::DLMALL
unsafe impl GlobalAlloc for System { unsafe impl GlobalAlloc for System {
#[inline] #[inline]
unsafe fn alloc(&self, layout: Layout) -> *mut u8 { 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] #[inline]
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { 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] #[inline]
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { 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] #[inline]
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { 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))] #[cfg(not(test))]
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn __rust_c_alloc(size: usize, align: usize) -> *mut u8 { 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))] #[cfg(not(test))]
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn __rust_c_dealloc(ptr: *mut u8, size: usize, align: usize) { 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)) }
} }

View File

@ -13,7 +13,7 @@ type ArgsStore = Vec<OsString>;
#[cfg_attr(test, allow(dead_code))] #[cfg_attr(test, allow(dead_code))]
pub unsafe fn init(argc: isize, argv: *const *const u8) { pub unsafe fn init(argc: isize, argv: *const *const u8) {
if argc != 0 { 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 let args = args
.iter() .iter()
.map(|a| OsString::from_inner(Buf { inner: a.copy_user_buffer() })) .map(|a| OsString::from_inner(Buf { inner: a.copy_user_buffer() }))

View File

@ -27,13 +27,13 @@ impl Condvar {
pub unsafe fn wait(&self, mutex: &Mutex) { pub unsafe fn wait(&self, mutex: &Mutex) {
let guard = self.inner.lock(); let guard = self.inner.lock();
WaitQueue::wait(guard, || mutex.unlock()); WaitQueue::wait(guard, || unsafe { mutex.unlock() });
mutex.lock() unsafe { mutex.lock() }
} }
pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
let success = WaitQueue::wait_timeout(&self.inner, dur, || mutex.unlock()); let success = WaitQueue::wait_timeout(&self.inner, dur, || unsafe { mutex.unlock() });
mutex.lock(); unsafe { mutex.lock() };
success success
} }

View File

@ -2,6 +2,7 @@
//! //!
//! This module contains the facade (aka platform-specific) implementations of //! This module contains the facade (aka platform-specific) implementations of
//! OS level functionality for Fortanix SGX. //! OS level functionality for Fortanix SGX.
#![deny(unsafe_op_in_unsafe_fn)]
use crate::io::ErrorKind; use crate::io::ErrorKind;
use crate::os::raw::c_char; use crate::os::raw::c_char;
@ -121,9 +122,9 @@ pub enum Void {}
pub unsafe fn strlen(mut s: *const c_char) -> usize { pub unsafe fn strlen(mut s: *const c_char) -> usize {
let mut n = 0; let mut n = 0;
while *s != 0 { while unsafe { *s } != 0 {
n += 1; n += 1;
s = s.offset(1); s = unsafe { s.offset(1) };
} }
return n; return n;
} }

View File

@ -14,9 +14,12 @@ pub struct RWLock {
} }
// Check at compile time that RWLock size matches C definition (see test_c_rwlock_initializer below) // 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)] #[allow(dead_code)]
unsafe fn rw_lock_size_assert(r: RWLock) { unsafe fn rw_lock_size_assert(r: RWLock) {
mem::transmute::<RWLock, [u8; 144]>(r); unsafe { mem::transmute::<RWLock, [u8; 144]>(r) };
} }
impl RWLock { impl RWLock {
@ -112,7 +115,7 @@ impl RWLock {
pub unsafe fn read_unlock(&self) { pub unsafe fn read_unlock(&self) {
let rguard = self.readers.lock(); let rguard = self.readers.lock();
let wguard = self.writer.lock(); let wguard = self.writer.lock();
self.__read_unlock(rguard, wguard); unsafe { self.__read_unlock(rguard, wguard) };
} }
#[inline] #[inline]
@ -148,7 +151,7 @@ impl RWLock {
pub unsafe fn write_unlock(&self) { pub unsafe fn write_unlock(&self) {
let rguard = self.readers.lock(); let rguard = self.readers.lock();
let wguard = self.writer.lock(); let wguard = self.writer.lock();
self.__write_unlock(rguard, wguard); unsafe { self.__write_unlock(rguard, wguard) };
} }
// only used by __rust_rwlock_unlock below // only used by __rust_rwlock_unlock below
@ -158,9 +161,9 @@ impl RWLock {
let rguard = self.readers.lock(); let rguard = self.readers.lock();
let wguard = self.writer.lock(); let wguard = self.writer.lock();
if *wguard.lock_var() == true { if *wguard.lock_var() == true {
self.__write_unlock(rguard, wguard); unsafe { self.__write_unlock(rguard, wguard) };
} else { } 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() { if p.is_null() {
return EINVAL; return EINVAL;
} }
(*p).read(); unsafe { (*p).read() };
return 0; return 0;
} }
@ -189,7 +192,7 @@ pub unsafe extern "C" fn __rust_rwlock_wrlock(p: *mut RWLock) -> i32 {
if p.is_null() { if p.is_null() {
return EINVAL; return EINVAL;
} }
(*p).write(); unsafe { (*p).write() };
return 0; return 0;
} }
#[cfg(not(test))] #[cfg(not(test))]
@ -198,6 +201,6 @@ pub unsafe extern "C" fn __rust_rwlock_unlock(p: *mut RWLock) -> i32 {
if p.is_null() { if p.is_null() {
return EINVAL; return EINVAL;
} }
(*p).unlock(); unsafe { (*p).unlock() };
return 0; return 0;
} }

View File

@ -81,7 +81,7 @@ pub unsafe extern "C" fn __rust_print_err(m: *mut u8, s: i32) {
if s < 0 { if s < 0 {
return; 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())]) { if let Ok(s) = str::from_utf8(&buf[..buf.iter().position(|&b| b == 0).unwrap_or(buf.len())]) {
eprint!("{}", s); eprint!("{}", s);
} }

View File

@ -51,7 +51,7 @@ impl Thread {
// unsafe: see thread::Builder::spawn_unchecked for safety requirements // unsafe: see thread::Builder::spawn_unchecked for safety requirements
pub unsafe fn new(_stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> { pub unsafe fn new(_stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
let mut queue_lock = task_queue::lock(); let mut queue_lock = task_queue::lock();
usercalls::launch_thread()?; unsafe { usercalls::launch_thread()? };
let (task, handle) = task_queue::Task::new(p); let (task, handle) = task_queue::Task::new(p);
queue_lock.push(task); queue_lock.push(task);
Ok(Thread(handle)) Ok(Thread(handle))

View File

@ -30,31 +30,34 @@ impl<T> UnsafeList<T> {
unsafe { UnsafeList { head_tail: NonNull::new_unchecked(1 as _), head_tail_entry: None } } unsafe { UnsafeList { head_tail: NonNull::new_unchecked(1 as _), head_tail_entry: None } }
} }
/// # Safety
unsafe fn init(&mut self) { unsafe fn init(&mut self) {
if self.head_tail_entry.is_none() { if self.head_tail_entry.is_none() {
self.head_tail_entry = Some(UnsafeListEntry::dummy()); self.head_tail_entry = Some(UnsafeListEntry::dummy());
self.head_tail = NonNull::new_unchecked(self.head_tail_entry.as_mut().unwrap()); // SAFETY: `head_tail_entry` must be non-null, which it is because we assign it above.
self.head_tail.as_mut().next = self.head_tail; self.head_tail =
self.head_tail.as_mut().prev = 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 { pub fn is_empty(&self) -> bool {
unsafe { if self.head_tail_entry.is_some() {
if self.head_tail_entry.is_some() { let first = unsafe { self.head_tail.as_ref() }.next;
let first = self.head_tail.as_ref().next; if first == self.head_tail {
if first == self.head_tail { // ,-------> /---------\ next ---,
// ,-------> /---------\ next ---, // | |head_tail| |
// | |head_tail| | // `--- prev \---------/ <-------`
// `--- prev \---------/ <-------` // SAFETY: `self.head_tail` must meet all requirements for a reference.
rtassert!(self.head_tail.as_ref().prev == first); unsafe { rtassert!(self.head_tail.as_ref().prev == first) };
true
} else {
false
}
} else {
true true
} else {
false
} }
} else {
true
} }
} }
@ -67,7 +70,7 @@ impl<T> UnsafeList<T> {
/// care must be taken in the caller of `push` to ensure unwinding does /// care must be taken in the caller of `push` to ensure unwinding does
/// not destroy the stack frame containing the entry. /// not destroy the stack frame containing the entry.
pub unsafe fn push<'a>(&mut self, entry: &'a mut UnsafeListEntry<T>) -> &'a T { pub unsafe fn push<'a>(&mut self, entry: &'a mut UnsafeListEntry<T>) -> &'a T {
self.init(); unsafe { self.init() };
// BEFORE: // BEFORE:
// /---------\ next ---> /---------\ // /---------\ next ---> /---------\
@ -78,13 +81,15 @@ impl<T> UnsafeList<T> {
// /---------\ next ---> /-----\ next ---> /---------\ // /---------\ next ---> /-----\ next ---> /---------\
// ... |prev_tail| |entry| |head_tail| ... // ... |prev_tail| |entry| |head_tail| ...
// \---------/ <--- prev \-----/ <--- prev \---------/ // \---------/ <--- prev \-----/ <--- prev \---------/
let mut entry = NonNull::new_unchecked(entry); let mut entry = unsafe { NonNull::new_unchecked(entry) };
let mut prev_tail = mem::replace(&mut self.head_tail.as_mut().prev, entry); let mut prev_tail = mem::replace(&mut unsafe { self.head_tail.as_mut() }.prev, entry);
entry.as_mut().prev = prev_tail; // SAFETY: `entry` must meet all requirements for a mutable reference.
entry.as_mut().next = self.head_tail; unsafe { entry.as_mut() }.prev = prev_tail;
prev_tail.as_mut().next = entry; 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 // 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. /// Pops an entry from the front of the list.
@ -94,7 +99,7 @@ impl<T> UnsafeList<T> {
/// The caller must make sure to synchronize ending the borrow of the /// The caller must make sure to synchronize ending the borrow of the
/// return value and deallocation of the containing entry. /// return value and deallocation of the containing entry.
pub unsafe fn pop<'a>(&mut self) -> Option<&'a T> { pub unsafe fn pop<'a>(&mut self) -> Option<&'a T> {
self.init(); unsafe { self.init() };
if self.is_empty() { if self.is_empty() {
None None
@ -108,14 +113,14 @@ impl<T> UnsafeList<T> {
// /---------\ next ---> /------\ // /---------\ next ---> /------\
// ... |head_tail| |second| ... // ... |head_tail| |second| ...
// \---------/ <--- prev \------/ // \---------/ <--- prev \------/
let mut first = self.head_tail.as_mut().next; let mut first = unsafe { self.head_tail.as_mut() }.next;
let mut second = first.as_mut().next; let mut second = unsafe { first.as_mut() }.next;
self.head_tail.as_mut().next = second; unsafe { self.head_tail.as_mut() }.next = second;
second.as_mut().prev = self.head_tail; unsafe { second.as_mut() }.prev = self.head_tail;
first.as_mut().next = NonNull::dangling(); unsafe { first.as_mut() }.next = NonNull::dangling();
first.as_mut().prev = NonNull::dangling(); unsafe { first.as_mut() }.prev = NonNull::dangling();
// unwrap ok: always `Some` on non-dummy entries // 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<T> UnsafeList<T> {
// \----/ <--- prev \----/ // \----/ <--- prev \----/
let mut prev = entry.prev; let mut prev = entry.prev;
let mut next = entry.next; let mut next = entry.next;
prev.as_mut().next = next; // SAFETY: `prev` and `next` must meet all requirements for a mutable reference.entry
next.as_mut().prev = prev; unsafe { prev.as_mut() }.next = next;
unsafe { next.as_mut() }.prev = prev;
entry.next = NonNull::dangling(); entry.next = NonNull::dangling();
entry.prev = NonNull::dangling(); entry.prev = NonNull::dangling();
} }

View File

@ -1,8 +1,10 @@
use super::*; use super::*;
use crate::cell::Cell; use crate::cell::Cell;
/// # Safety
/// List must be valid.
unsafe fn assert_empty<T>(list: &mut UnsafeList<T>) { unsafe fn assert_empty<T>(list: &mut UnsafeList<T>) {
assert!(list.pop().is_none(), "assertion failed: list is not empty"); assert!(unsafe { list.pop() }.is_none(), "assertion failed: list is not empty");
} }
#[test] #[test]