diff --git a/library/std/src/sys_common/alloc.rs b/library/std/src/sys_common/alloc.rs index c669410078592..9eea702953402 100644 --- a/library/std/src/sys_common/alloc.rs +++ b/library/std/src/sys_common/alloc.rs @@ -33,14 +33,25 @@ pub unsafe fn realloc_fallback( old_layout: Layout, new_size: usize, ) -> *mut u8 { - // Docs for GlobalAlloc::realloc require this to be valid: - let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align()); + // SAFETY: as stated in docs for GlobalAlloc::realloc, the caller + // must guarantee that `new_size` is valid for a `Layout`. + // The `old_layout.align()` is guaranteed to be valid as it comes + // from a `Layout`. + let new_layout = unsafe { Layout::from_size_align_unchecked(new_size, old_layout.align()) }; - let new_ptr = GlobalAlloc::alloc(alloc, new_layout); + // SAFETY: as stated in docs for GlobalAlloc::realloc, the caller + // must guarantee that `new_size` is greater than zero. + let new_ptr = unsafe { GlobalAlloc::alloc(alloc, new_layout) }; if !new_ptr.is_null() { let size = cmp::min(old_layout.size(), new_size); - ptr::copy_nonoverlapping(ptr, new_ptr, size); - GlobalAlloc::dealloc(alloc, ptr, old_layout); + // SAFETY: the newly allocated memory cannot overlap the previously + // allocated memory. Also, the call to `dealloc` is safe since + // the caller must guarantee that `ptr` is allocated via this allocator + // and layout is the same layout that was used to allocate `ptr`. + unsafe { + ptr::copy_nonoverlapping(ptr, new_ptr, size); + GlobalAlloc::dealloc(alloc, ptr, old_layout); + } } new_ptr } diff --git a/library/std/src/sys_common/at_exit_imp.rs b/library/std/src/sys_common/at_exit_imp.rs index 6b799db856eb1..db85af980ece7 100644 --- a/library/std/src/sys_common/at_exit_imp.rs +++ b/library/std/src/sys_common/at_exit_imp.rs @@ -26,10 +26,14 @@ const DONE: *mut Queue = 1_usize as *mut _; const ITERS: usize = 10; unsafe fn init() -> bool { - if QUEUE.is_null() { + // SAFETY: the caller must ensure that `QUEUE` is not in use anywhere else, + // which `push` below does by locking `LOCK`. + if unsafe { QUEUE.is_null() } { let state: Box = box Vec::new(); - QUEUE = Box::into_raw(state); - } else if QUEUE == DONE { + unsafe { + QUEUE = Box::into_raw(state); + } + } else if unsafe { QUEUE == DONE } { // can't re-init after a cleanup return false; } diff --git a/library/std/src/sys_common/backtrace.rs b/library/std/src/sys_common/backtrace.rs index 1c5fbf7d70102..34ce80291d16d 100644 --- a/library/std/src/sys_common/backtrace.rs +++ b/library/std/src/sys_common/backtrace.rs @@ -76,44 +76,46 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt:: let mut res = Ok(()); // Start immediately if we're not using a short backtrace. let mut start = print_fmt != PrintFmt::Short; - backtrace_rs::trace_unsynchronized(|frame| { - if print_fmt == PrintFmt::Short && idx > MAX_NB_FRAMES { - return false; - } + unsafe { + backtrace_rs::trace_unsynchronized(|frame| { + if print_fmt == PrintFmt::Short && idx > MAX_NB_FRAMES { + return false; + } - let mut hit = false; - let mut stop = false; - backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| { - hit = true; - if print_fmt == PrintFmt::Short { - if let Some(sym) = symbol.name().and_then(|s| s.as_str()) { - if sym.contains("__rust_begin_short_backtrace") { - stop = true; - return; - } - if sym.contains("__rust_end_short_backtrace") { - start = true; - return; + let mut hit = false; + let mut stop = false; + backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| { + hit = true; + if print_fmt == PrintFmt::Short { + if let Some(sym) = symbol.name().and_then(|s| s.as_str()) { + if sym.contains("__rust_begin_short_backtrace") { + stop = true; + return; + } + if sym.contains("__rust_end_short_backtrace") { + start = true; + return; + } } } - } - if start { - res = bt_fmt.frame().symbol(frame, symbol); + if start { + res = bt_fmt.frame().symbol(frame, symbol); + } + }); + if stop { + return false; } - }); - if stop { - return false; - } - if !hit { - if start { - res = bt_fmt.frame().print_raw(frame.ip(), None, None, None); + if !hit { + if start { + res = bt_fmt.frame().print_raw(frame.ip(), None, None, None); + } } - } - idx += 1; - res.is_ok() - }); + idx += 1; + res.is_ok() + }); + } res?; bt_fmt.finish()?; if print_fmt == PrintFmt::Short { diff --git a/library/std/src/sys_common/condvar.rs b/library/std/src/sys_common/condvar.rs index f9611bc6f7bc9..ddd6c37545c8d 100644 --- a/library/std/src/sys_common/condvar.rs +++ b/library/std/src/sys_common/condvar.rs @@ -25,19 +25,22 @@ impl Condvar { /// address. #[inline] pub unsafe fn init(&mut self) { - self.0.init() + // SAFETY: the caller must uphold the safety contract for `init`. + unsafe { self.0.init() } } /// Signals one waiter on this condition variable to wake up. #[inline] pub unsafe fn notify_one(&self) { - self.0.notify_one() + // SAFETY: the caller must uphold the safety contract for `notify_one`. + unsafe { self.0.notify_one() } } /// Awakens all current waiters on this condition variable. #[inline] pub unsafe fn notify_all(&self) { - self.0.notify_all() + // SAFETY: the caller must uphold the safety contract for `notify_all`. + unsafe { self.0.notify_all() } } /// Waits for a signal on the specified mutex. @@ -47,7 +50,8 @@ impl Condvar { /// on this condition variable. #[inline] pub unsafe fn wait(&self, mutex: &Mutex) { - self.0.wait(mutex::raw(mutex)) + // SAFETY: the caller must uphold the safety contract for `wait`. + unsafe { self.0.wait(mutex::raw(mutex)) } } /// Waits for a signal on the specified mutex with a timeout duration @@ -58,7 +62,8 @@ impl Condvar { /// on this condition variable. #[inline] pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { - self.0.wait_timeout(mutex::raw(mutex), dur) + // SAFETY: the caller must uphold the safety contract for `wait_timeout`. + unsafe { self.0.wait_timeout(mutex::raw(mutex), dur) } } /// Deallocates all resources associated with this condition variable. @@ -67,6 +72,7 @@ impl Condvar { /// this condition variable. #[inline] pub unsafe fn destroy(&self) { - self.0.destroy() + // SAFETY: the caller must uphold the safety contract for `destroy`. + unsafe { self.0.destroy() } } } diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs index 28cdfefb12a08..0023ea3359a59 100644 --- a/library/std/src/sys_common/mod.rs +++ b/library/std/src/sys_common/mod.rs @@ -14,6 +14,7 @@ #![allow(missing_docs)] #![allow(missing_debug_implementations)] +#![deny(unsafe_op_in_unsafe_fn)] #[cfg(test)] mod tests; diff --git a/library/std/src/sys_common/mutex.rs b/library/std/src/sys_common/mutex.rs index e66d8994147e1..b9e70c935acd2 100644 --- a/library/std/src/sys_common/mutex.rs +++ b/library/std/src/sys_common/mutex.rs @@ -30,7 +30,8 @@ impl Mutex { /// `init()`) is undefined behavior. #[inline] pub unsafe fn init(&mut self) { - self.0.init() + // SAFETY: the caller must uphold the safety contract for `init`. + unsafe { self.0.init() } } /// Locks the mutex blocking the current thread until it is available. @@ -39,14 +40,18 @@ impl Mutex { /// previous function call. #[inline] pub unsafe fn raw_lock(&self) { - self.0.lock() + // SAFETY: the caller must uphold the safety contract for `lock`. + unsafe { self.0.lock() } } /// Calls raw_lock() and then returns an RAII guard to guarantee the mutex /// will be unlocked. #[inline] pub unsafe fn lock(&self) -> MutexGuard<'_> { - self.raw_lock(); + // SAFETY: the caller must uphold the safety contract for `raw_lock`. + unsafe { + self.raw_lock(); + } MutexGuard(&self.0) } @@ -57,7 +62,8 @@ impl Mutex { /// previous function call. #[inline] pub unsafe fn try_lock(&self) -> bool { - self.0.try_lock() + // SAFETY: the caller must uphold the safety contract for `try_lock`. + unsafe { self.0.try_lock() } } /// Unlocks the mutex. @@ -69,7 +75,8 @@ impl Mutex { /// lock() whenever possible. #[inline] pub unsafe fn raw_unlock(&self) { - self.0.unlock() + // SAFETY: the caller must uphold the safety contract for `unlock`. + unsafe { self.0.unlock() } } /// Deallocates all resources associated with this mutex. @@ -78,7 +85,8 @@ impl Mutex { /// this mutex. #[inline] pub unsafe fn destroy(&self) { - self.0.destroy() + // SAFETY: the caller must uphold the safety contract for `destroy`. + unsafe { self.0.destroy() } } } diff --git a/library/std/src/sys_common/remutex.rs b/library/std/src/sys_common/remutex.rs index 360337c030be4..13ffd22df519b 100644 --- a/library/std/src/sys_common/remutex.rs +++ b/library/std/src/sys_common/remutex.rs @@ -53,7 +53,12 @@ impl ReentrantMutex { /// once this mutex is in its final resting place, and only then are the /// lock/unlock methods safe. pub const unsafe fn new(t: T) -> ReentrantMutex { - ReentrantMutex { inner: sys::ReentrantMutex::uninitialized(), data: t } + // `ReentrantMutex::uninitialized()` is not unsafe on all platforms + #[allow(unused_unsafe)] + // SAFETY: the caller must guarantee that `init` is called. + unsafe { + ReentrantMutex { inner: sys::ReentrantMutex::uninitialized(), data: t } + } } /// Initializes this mutex so it's ready for use. @@ -63,7 +68,8 @@ impl ReentrantMutex { /// Unsafe to call more than once, and must be called after this will no /// longer move in memory. pub unsafe fn init(&self) { - self.inner.init(); + // SAFETY: the caller must uphold the safety contract for `init`. + unsafe { self.inner.init() }; } /// Acquires a mutex, blocking the current thread until it is able to do so. @@ -79,6 +85,7 @@ impl ReentrantMutex { /// this call will return failure if the mutex would otherwise be /// acquired. pub fn lock(&self) -> ReentrantMutexGuard<'_, T> { + // SAFETY: the caller must uphold the safety contract for `lock`. unsafe { self.inner.lock() } ReentrantMutexGuard::new(&self) } diff --git a/library/std/src/sys_common/rwlock.rs b/library/std/src/sys_common/rwlock.rs index 3705d641a1be6..b5376d8d62c52 100644 --- a/library/std/src/sys_common/rwlock.rs +++ b/library/std/src/sys_common/rwlock.rs @@ -23,7 +23,8 @@ impl RWLock { /// previous method call. #[inline] pub unsafe fn read(&self) { - self.0.read() + // SAFETY: the caller must uphold the safety contract for `read`. + unsafe { self.0.read() } } /// Attempts to acquire shared access to this lock, returning whether it @@ -35,7 +36,8 @@ impl RWLock { /// previous method call. #[inline] pub unsafe fn try_read(&self) -> bool { - self.0.try_read() + // SAFETY: the caller must uphold the safety contract for `try_read`. + unsafe { self.0.try_read() } } /// Acquires write access to the underlying lock, blocking the current thread @@ -45,7 +47,8 @@ impl RWLock { /// previous method call. #[inline] pub unsafe fn write(&self) { - self.0.write() + // SAFETY: the caller must uphold the safety contract for `write`. + unsafe { self.0.write() } } /// Attempts to acquire exclusive access to this lock, returning whether it @@ -57,7 +60,8 @@ impl RWLock { /// previous method call. #[inline] pub unsafe fn try_write(&self) -> bool { - self.0.try_write() + // SAFETY: the caller must uphold the safety contract for `try_write`. + unsafe { self.0.try_write() } } /// Unlocks previously acquired shared access to this lock. @@ -65,7 +69,8 @@ impl RWLock { /// Behavior is undefined if the current thread does not have shared access. #[inline] pub unsafe fn read_unlock(&self) { - self.0.read_unlock() + // SAFETY: the caller must uphold the safety contract for `read_unlock`. + unsafe { self.0.read_unlock() } } /// Unlocks previously acquired exclusive access to this lock. @@ -74,7 +79,8 @@ impl RWLock { /// exclusive access. #[inline] pub unsafe fn write_unlock(&self) { - self.0.write_unlock() + // SAFETY: the caller must uphold the safety contract for `write_unlock`. + unsafe { self.0.write_unlock() } } /// Destroys OS-related resources with this RWLock. @@ -83,6 +89,7 @@ impl RWLock { /// lock. #[inline] pub unsafe fn destroy(&self) { - self.0.destroy() + // SAFETY: the caller must uphold the safety contract for `destroy`. + unsafe { self.0.destroy() } } } diff --git a/library/std/src/sys_common/thread_info.rs b/library/std/src/sys_common/thread_info.rs index f09d16c33e6d6..8118dff03a9aa 100644 --- a/library/std/src/sys_common/thread_info.rs +++ b/library/std/src/sys_common/thread_info.rs @@ -1,4 +1,8 @@ -#![allow(dead_code)] // stack_guard isn't used right now on all platforms +// stack_guard isn't used right now on all platforms +#![allow(dead_code)] +// FIXME: this should be removed once `thread_local!` denies unsafe ops in unsafe +// fns. This cannot be done yet because the macro is also used in libproc_macro. +#![allow(unsafe_op_in_unsafe_fn)] use crate::cell::RefCell; use crate::sys::thread::guard::Guard; diff --git a/library/std/src/sys_common/thread_local_dtor.rs b/library/std/src/sys_common/thread_local_dtor.rs index 6f5ebf4a27158..d02f8a1cf75dd 100644 --- a/library/std/src/sys_common/thread_local_dtor.rs +++ b/library/std/src/sys_common/thread_local_dtor.rs @@ -29,21 +29,25 @@ pub unsafe fn register_dtor_fallback(t: *mut u8, dtor: unsafe extern "C" fn(*mut static DTORS: StaticKey = StaticKey::new(Some(run_dtors)); type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>; - if DTORS.get().is_null() { + if unsafe { DTORS.get().is_null() } { let v: Box = box Vec::new(); - DTORS.set(Box::into_raw(v) as *mut u8); + unsafe { DTORS.set(Box::into_raw(v) as *mut u8) } } - let list: &mut List = &mut *(DTORS.get() as *mut List); + let list: &mut List = unsafe { &mut *(DTORS.get() as *mut List) }; list.push((t, dtor)); unsafe extern "C" fn run_dtors(mut ptr: *mut u8) { while !ptr.is_null() { - let list: Box = Box::from_raw(ptr as *mut List); + let list: Box = unsafe { Box::from_raw(ptr as *mut List) }; for (ptr, dtor) in list.into_iter() { - dtor(ptr); + unsafe { + dtor(ptr); + } + } + unsafe { + ptr = DTORS.get(); + DTORS.set(ptr::null_mut()); } - ptr = DTORS.get(); - DTORS.set(ptr::null_mut()); } } } diff --git a/library/std/src/sys_common/thread_local_key.rs b/library/std/src/sys_common/thread_local_key.rs index 3a2218854a730..7a375f600b697 100644 --- a/library/std/src/sys_common/thread_local_key.rs +++ b/library/std/src/sys_common/thread_local_key.rs @@ -127,7 +127,8 @@ impl StaticKey { /// been allocated. #[inline] pub unsafe fn get(&self) -> *mut u8 { - imp::get(self.key()) + // SAFETY: the caller must uphold the safety contract for `get`. + unsafe { imp::get(self.key()) } } /// Sets this TLS key to a new value. @@ -136,13 +137,16 @@ impl StaticKey { /// been allocated. #[inline] pub unsafe fn set(&self, val: *mut u8) { - imp::set(self.key(), val) + // SAFETY: the caller must uphold the safety contract for `set`. + unsafe { imp::set(self.key(), val) } } #[inline] unsafe fn key(&self) -> imp::Key { match self.key.load(Ordering::Relaxed) { - 0 => self.lazy_init() as imp::Key, + // SAFETY: `0` is used as a sentinel value for an unitialized value, + // which means that initializing it is safe. + 0 => unsafe { self.lazy_init() as imp::Key }, n => n as imp::Key, } } @@ -157,10 +161,13 @@ impl StaticKey { // We never call `INIT_LOCK.init()`, so it is UB to attempt to // acquire this mutex reentrantly! static INIT_LOCK: Mutex = Mutex::new(); - let _guard = INIT_LOCK.lock(); + + // SAFETY: `INIT_LOCK` is an immutable static thus the + // mutex cannot be moved. + let _guard = unsafe { INIT_LOCK.lock() }; let mut key = self.key.load(Ordering::SeqCst); if key == 0 { - key = imp::create(self.dtor) as usize; + key = unsafe { imp::create(self.dtor) as usize }; self.key.store(key, Ordering::SeqCst); } rtassert!(key != 0); @@ -176,13 +183,15 @@ impl StaticKey { // value of 0, but with some gyrations to make sure we have a non-0 // value returned from the creation routine. // FIXME: this is clearly a hack, and should be cleaned up. - let key1 = imp::create(self.dtor); + let key1 = unsafe { imp::create(self.dtor) }; let key = if key1 != 0 { key1 } else { - let key2 = imp::create(self.dtor); - imp::destroy(key1); - key2 + unsafe { + let key2 = imp::create(self.dtor); + imp::destroy(key1); + key2 + } }; rtassert!(key != 0); match self.key.compare_and_swap(0, key as usize, Ordering::SeqCst) { @@ -190,7 +199,9 @@ impl StaticKey { 0 => key as usize, // If someone beat us to the punch, use their key instead n => { - imp::destroy(key); + unsafe { + imp::destroy(key); + } n } } diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs index 7d4b0d5283199..086a01eebd659 100644 --- a/library/std/src/sys_common/wtf8.rs +++ b/library/std/src/sys_common/wtf8.rs @@ -480,7 +480,8 @@ impl Wtf8 { /// marked unsafe. #[inline] unsafe fn from_bytes_unchecked(value: &[u8]) -> &Wtf8 { - mem::transmute(value) + // SAFETY: the caller must guarantee that `value` is a valid WTF-8 value. + unsafe { mem::transmute(value) } } /// Creates a mutable WTF-8 slice from a mutable WTF-8 byte slice. @@ -489,7 +490,8 @@ impl Wtf8 { /// marked unsafe. #[inline] unsafe fn from_mut_bytes_unchecked(value: &mut [u8]) -> &mut Wtf8 { - mem::transmute(value) + // SAFETY: the caller must guarantee that `value` is a valid WTF-8 value. + unsafe { mem::transmute(value) } } /// Returns the length, in WTF-8 bytes. @@ -785,8 +787,10 @@ pub fn is_code_point_boundary(slice: &Wtf8, index: usize) -> bool { /// Copied from core::str::raw::slice_unchecked #[inline] pub unsafe fn slice_unchecked(s: &Wtf8, begin: usize, end: usize) -> &Wtf8 { - // memory layout of an &[u8] and &Wtf8 are the same - Wtf8::from_bytes_unchecked(slice::from_raw_parts(s.bytes.as_ptr().add(begin), end - begin)) + // SAFETY: the memory layout of an &[u8] and &Wtf8 are the same + unsafe { + Wtf8::from_bytes_unchecked(slice::from_raw_parts(s.bytes.as_ptr().add(begin), end - begin)) + } } /// Copied from core::str::raw::slice_error_fail