Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

std: #![deny(unsafe_op_in_unsafe_fn)] in platform-independent code #127744

Merged
merged 7 commits into from
Jul 15, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion library/std/src/collections/hash/map.rs
Original file line number Diff line number Diff line change
@@ -1018,7 +1018,7 @@ where
K: Borrow<Q>,
Q: Hash + Eq,
{
self.base.get_many_unchecked_mut(ks)
unsafe { self.base.get_many_unchecked_mut(ks) }
}

/// Returns `true` if the map contains a value for the specified key.
14 changes: 4 additions & 10 deletions library/std/src/env.rs
Original file line number Diff line number Diff line change
@@ -366,11 +366,8 @@ impl Error for VarError {
#[rustc_deprecated_safe_2024]
#[stable(feature = "env", since = "1.0.0")]
pub unsafe fn set_var<K: AsRef<OsStr>, V: AsRef<OsStr>>(key: K, value: V) {
_set_var(key.as_ref(), value.as_ref())
}

unsafe fn _set_var(key: &OsStr, value: &OsStr) {
os_imp::setenv(key, value).unwrap_or_else(|e| {
Comment on lines -369 to -373
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're afraid of a little monomorphization here then we have hundreds more cases that are currently like this. We should write an internal lint for it and then fix all the lint sites.

let (key, value) = (key.as_ref(), value.as_ref());
unsafe { os_imp::setenv(key, value) }.unwrap_or_else(|e| {
panic!("failed to set environment variable `{key:?}` to `{value:?}`: {e}")
})
}
@@ -433,11 +430,8 @@ unsafe fn _set_var(key: &OsStr, value: &OsStr) {
#[rustc_deprecated_safe_2024]
#[stable(feature = "env", since = "1.0.0")]
pub unsafe fn remove_var<K: AsRef<OsStr>>(key: K) {
_remove_var(key.as_ref())
}

unsafe fn _remove_var(key: &OsStr) {
os_imp::unsetenv(key)
let key = key.as_ref();
unsafe { os_imp::unsetenv(key) }
.unwrap_or_else(|e| panic!("failed to remove environment variable `{key:?}`: {e}"))
}

4 changes: 2 additions & 2 deletions library/std/src/ffi/os_str.rs
Original file line number Diff line number Diff line change
@@ -184,7 +184,7 @@ impl OsString {
#[inline]
#[stable(feature = "os_str_bytes", since = "1.74.0")]
pub unsafe fn from_encoded_bytes_unchecked(bytes: Vec<u8>) -> Self {
OsString { inner: Buf::from_encoded_bytes_unchecked(bytes) }
OsString { inner: unsafe { Buf::from_encoded_bytes_unchecked(bytes) } }
}

/// Converts to an [`OsStr`] slice.
@@ -813,7 +813,7 @@ impl OsStr {
#[inline]
#[stable(feature = "os_str_bytes", since = "1.74.0")]
pub unsafe fn from_encoded_bytes_unchecked(bytes: &[u8]) -> &Self {
Self::from_inner(Slice::from_encoded_bytes_unchecked(bytes))
Self::from_inner(unsafe { Slice::from_encoded_bytes_unchecked(bytes) })
}

#[inline]
8 changes: 5 additions & 3 deletions library/std/src/io/buffered/bufwriter.rs
Original file line number Diff line number Diff line change
@@ -433,9 +433,11 @@ impl<W: ?Sized + Write> BufWriter<W> {
let old_len = self.buf.len();
let buf_len = buf.len();
let src = buf.as_ptr();
let dst = self.buf.as_mut_ptr().add(old_len);
ptr::copy_nonoverlapping(src, dst, buf_len);
self.buf.set_len(old_len + buf_len);
unsafe {
let dst = self.buf.as_mut_ptr().add(old_len);
ptr::copy_nonoverlapping(src, dst, buf_len);
self.buf.set_len(old_len + buf_len);
}
}

#[inline]
2 changes: 1 addition & 1 deletion library/std/src/io/cursor.rs
Original file line number Diff line number Diff line change
@@ -482,7 +482,7 @@ where
A: Allocator,
{
debug_assert!(vec.capacity() >= pos + buf.len());
vec.as_mut_ptr().add(pos).copy_from(buf.as_ptr(), buf.len());
unsafe { vec.as_mut_ptr().add(pos).copy_from(buf.as_ptr(), buf.len()) };
pos + buf.len()
}

7 changes: 5 additions & 2 deletions library/std/src/io/error/repr_bitpacked.rs
Original file line number Diff line number Diff line change
@@ -267,11 +267,14 @@ where
// Using this rather than unwrap meaningfully improves the code
// for callers which only care about one variant (usually
// `Custom`)
core::hint::unreachable_unchecked();
unsafe { core::hint::unreachable_unchecked() };
});
ErrorData::Simple(kind)
}
TAG_SIMPLE_MESSAGE => ErrorData::SimpleMessage(&*ptr.cast::<SimpleMessage>().as_ptr()),
TAG_SIMPLE_MESSAGE => {
// SAFETY: per tag
unsafe { ErrorData::SimpleMessage(&*ptr.cast::<SimpleMessage>().as_ptr()) }
}
TAG_CUSTOM => {
// It would be correct for us to use `ptr::byte_sub` here (see the
// comment above the `wrapping_add` call in `new_custom` for why),
4 changes: 2 additions & 2 deletions library/std/src/io/mod.rs
Original file line number Diff line number Diff line change
@@ -382,11 +382,11 @@ pub(crate) unsafe fn append_to_string<F>(buf: &mut String, f: F) -> Result<usize
where
F: FnOnce(&mut Vec<u8>) -> Result<usize>,
{
let mut g = Guard { len: buf.len(), buf: buf.as_mut_vec() };
let mut g = Guard { len: buf.len(), buf: unsafe { buf.as_mut_vec() } };
let ret = f(g.buf);

// SAFETY: the caller promises to only append data to `buf`
let appended = g.buf.get_unchecked(g.len..);
let appended = unsafe { g.buf.get_unchecked(g.len..) };
if str::from_utf8(appended).is_err() {
ret.and_then(|_| Err(Error::INVALID_UTF8))
} else {
3 changes: 2 additions & 1 deletion library/std/src/lib.rs
Original file line number Diff line number Diff line change
@@ -252,6 +252,7 @@
#![allow(internal_features)]
#![deny(rustc::existing_doc_keyword)]
#![deny(fuzzy_provenance_casts)]
#![deny(unsafe_op_in_unsafe_fn)]
#![allow(rustdoc::redundant_explicit_links)]
// Ensure that std can be linked against panic_abort despite compiled with `-C panic=unwind`
#![deny(ffi_unwind_calls)]
@@ -664,7 +665,7 @@ pub mod alloc;
mod panicking;

#[path = "../../backtrace/src/lib.rs"]
#[allow(dead_code, unused_attributes, fuzzy_provenance_casts)]
#[allow(dead_code, unused_attributes, fuzzy_provenance_casts, unsafe_op_in_unsafe_fn)]
mod backtrace_rs;

// Re-export macros defined in core.
1 change: 1 addition & 0 deletions library/std/src/os/mod.rs
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@
#![stable(feature = "os", since = "1.0.0")]
#![allow(missing_docs, nonstandard_style, missing_debug_implementations)]
#![allow(unsafe_op_in_unsafe_fn)]

pub mod raw;

22 changes: 13 additions & 9 deletions library/std/src/sync/mpmc/array.rs
Original file line number Diff line number Diff line change
@@ -200,11 +200,12 @@ impl<T> Channel<T> {
return Err(msg);
}

let slot: &Slot<T> = &*(token.array.slot as *const Slot<T>);

// Write the message into the slot and update the stamp.
slot.msg.get().write(MaybeUninit::new(msg));
slot.stamp.store(token.array.stamp, Ordering::Release);
unsafe {
let slot: &Slot<T> = &*(token.array.slot as *const Slot<T>);
slot.msg.get().write(MaybeUninit::new(msg));
slot.stamp.store(token.array.stamp, Ordering::Release);
}

// Wake a sleeping receiver.
self.receivers.notify();
@@ -291,11 +292,14 @@ impl<T> Channel<T> {
return Err(());
}

let slot: &Slot<T> = &*(token.array.slot as *const Slot<T>);

// Read the message from the slot and update the stamp.
let msg = slot.msg.get().read().assume_init();
slot.stamp.store(token.array.stamp, Ordering::Release);
let msg = unsafe {
let slot: &Slot<T> = &*(token.array.slot as *const Slot<T>);

let msg = slot.msg.get().read().assume_init();
slot.stamp.store(token.array.stamp, Ordering::Release);
msg
};

// Wake a sleeping sender.
self.senders.notify();
@@ -471,7 +475,7 @@ impl<T> Channel<T> {
false
};

self.discard_all_messages(tail);
unsafe { self.discard_all_messages(tail) };
disconnected
}

4 changes: 2 additions & 2 deletions library/std/src/sync/mpmc/counter.rs
Original file line number Diff line number Diff line change
@@ -63,7 +63,7 @@ impl<C> Sender<C> {
disconnect(&self.counter().chan);

if self.counter().destroy.swap(true, Ordering::AcqRel) {
drop(Box::from_raw(self.counter));
drop(unsafe { Box::from_raw(self.counter) });
}
}
}
@@ -116,7 +116,7 @@ impl<C> Receiver<C> {
disconnect(&self.counter().chan);

if self.counter().destroy.swap(true, Ordering::AcqRel) {
drop(Box::from_raw(self.counter));
drop(unsafe { Box::from_raw(self.counter) });
}
}
}
38 changes: 21 additions & 17 deletions library/std/src/sync/mpmc/list.rs
Original file line number Diff line number Diff line change
@@ -91,7 +91,7 @@ impl<T> Block<T> {
// It is not necessary to set the `DESTROY` bit in the last slot because that slot has
// begun destruction of the block.
for i in start..BLOCK_CAP - 1 {
let slot = (*this).slots.get_unchecked(i);
let slot = unsafe { (*this).slots.get_unchecked(i) };

// Mark the `DESTROY` bit if a thread is still using the slot.
if slot.state.load(Ordering::Acquire) & READ == 0
@@ -103,7 +103,7 @@ impl<T> Block<T> {
}

// No thread is using the block, now it is safe to destroy it.
drop(Box::from_raw(this));
drop(unsafe { Box::from_raw(this) });
}
}

@@ -265,9 +265,11 @@ impl<T> Channel<T> {
// Write the message into the slot.
let block = token.list.block as *mut Block<T>;
let offset = token.list.offset;
let slot = (*block).slots.get_unchecked(offset);
slot.msg.get().write(MaybeUninit::new(msg));
slot.state.fetch_or(WRITE, Ordering::Release);
unsafe {
let slot = (*block).slots.get_unchecked(offset);
slot.msg.get().write(MaybeUninit::new(msg));
slot.state.fetch_or(WRITE, Ordering::Release);
}

// Wake a sleeping receiver.
self.receivers.notify();
@@ -369,19 +371,21 @@ impl<T> Channel<T> {
// Read the message.
let block = token.list.block as *mut Block<T>;
let offset = token.list.offset;
let slot = (*block).slots.get_unchecked(offset);
slot.wait_write();
let msg = slot.msg.get().read().assume_init();

// Destroy the block if we've reached the end, or if another thread wanted to destroy but
// couldn't because we were busy reading from the slot.
if offset + 1 == BLOCK_CAP {
Block::destroy(block, 0);
} else if slot.state.fetch_or(READ, Ordering::AcqRel) & DESTROY != 0 {
Block::destroy(block, offset + 1);
}
unsafe {
let slot = (*block).slots.get_unchecked(offset);
slot.wait_write();
let msg = slot.msg.get().read().assume_init();

// Destroy the block if we've reached the end, or if another thread wanted to destroy but
// couldn't because we were busy reading from the slot.
if offset + 1 == BLOCK_CAP {
Block::destroy(block, 0);
} else if slot.state.fetch_or(READ, Ordering::AcqRel) & DESTROY != 0 {
Block::destroy(block, offset + 1);
}

Ok(msg)
Ok(msg)
}
}

/// Attempts to send a message into the channel.
20 changes: 12 additions & 8 deletions library/std/src/sync/mpmc/zero.rs
Original file line number Diff line number Diff line change
@@ -103,9 +103,11 @@ impl<T> Channel<T> {
return Err(msg);
}

let packet = &*(token.zero.0 as *const Packet<T>);
packet.msg.get().write(Some(msg));
packet.ready.store(true, Ordering::Release);
unsafe {
let packet = &*(token.zero.0 as *const Packet<T>);
packet.msg.get().write(Some(msg));
packet.ready.store(true, Ordering::Release);
}
Ok(())
}

@@ -116,22 +118,24 @@ impl<T> Channel<T> {
return Err(());
}

let packet = &*(token.zero.0 as *const Packet<T>);
let packet = unsafe { &*(token.zero.0 as *const Packet<T>) };

if packet.on_stack {
// The message has been in the packet from the beginning, so there is no need to wait
// for it. However, after reading the message, we need to set `ready` to `true` in
// order to signal that the packet can be destroyed.
let msg = packet.msg.get().replace(None).unwrap();
let msg = unsafe { packet.msg.get().replace(None) }.unwrap();
packet.ready.store(true, Ordering::Release);
Ok(msg)
} else {
// Wait until the message becomes available, then read it and destroy the
// heap-allocated packet.
packet.wait_ready();
let msg = packet.msg.get().replace(None).unwrap();
drop(Box::from_raw(token.zero.0 as *mut Packet<T>));
Ok(msg)
unsafe {
let msg = packet.msg.get().replace(None).unwrap();
drop(Box::from_raw(token.zero.0 as *mut Packet<T>));
Ok(msg)
}
}
}

4 changes: 2 additions & 2 deletions library/std/src/sync/once_lock.rs
Original file line number Diff line number Diff line change
@@ -502,7 +502,7 @@ impl<T> OnceLock<T> {
#[inline]
unsafe fn get_unchecked(&self) -> &T {
debug_assert!(self.is_initialized());
(&*self.value.get()).assume_init_ref()
unsafe { (&*self.value.get()).assume_init_ref() }
}

/// # Safety
@@ -511,7 +511,7 @@ impl<T> OnceLock<T> {
#[inline]
unsafe fn get_unchecked_mut(&mut self) -> &mut T {
debug_assert!(self.is_initialized());
(&mut *self.value.get()).assume_init_mut()
unsafe { (&mut *self.value.get()).assume_init_mut() }
}
}

4 changes: 3 additions & 1 deletion library/std/src/sync/reentrant_lock.rs
Original file line number Diff line number Diff line change
@@ -244,7 +244,9 @@ impl<T: ?Sized> ReentrantLock<T> {
}

unsafe fn increment_lock_count(&self) -> Option<()> {
*self.lock_count.get() = (*self.lock_count.get()).checked_add(1)?;
unsafe {
*self.lock_count.get() = (*self.lock_count.get()).checked_add(1)?;
}
Some(())
}
}
2 changes: 1 addition & 1 deletion library/std/src/sync/rwlock.rs
Original file line number Diff line number Diff line change
@@ -578,7 +578,7 @@ impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> {
// successfully called from the same thread before instantiating this object.
unsafe fn new(lock: &'rwlock RwLock<T>) -> LockResult<RwLockReadGuard<'rwlock, T>> {
poison::map_result(lock.poison.borrow(), |()| RwLockReadGuard {
data: NonNull::new_unchecked(lock.data.get()),
data: unsafe { NonNull::new_unchecked(lock.data.get()) },
inner_lock: &lock.inner,
})
}
2 changes: 2 additions & 0 deletions library/std/src/sys/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![allow(unsafe_op_in_unsafe_fn)]

/// The PAL (platform abstraction layer) contains platform-specific abstractions
/// for implementing the features in the other submodules, e.g. UNIX file
/// descriptors.
14 changes: 10 additions & 4 deletions library/std/src/sys_common/wtf8.rs
Original file line number Diff line number Diff line change
@@ -602,7 +602,8 @@ impl Wtf8 {
/// marked unsafe.
#[inline]
pub unsafe fn from_bytes_unchecked(value: &[u8]) -> &Wtf8 {
mem::transmute(value)
// SAFETY: start with &[u8], end with fancy &[u8]
unsafe { &*(value as *const [u8] as *const Wtf8) }
}

/// Creates a mutable WTF-8 slice from a mutable WTF-8 byte slice.
@@ -611,7 +612,8 @@ impl Wtf8 {
/// marked unsafe.
#[inline]
unsafe fn from_mut_bytes_unchecked(value: &mut [u8]) -> &mut Wtf8 {
mem::transmute(value)
// SAFETY: start with &mut [u8], end with fancy &mut [u8]
unsafe { &mut *(value as *mut [u8] as *mut Wtf8) }
}

/// Returns the length, in WTF-8 bytes.
@@ -942,8 +944,12 @@ pub fn check_utf8_boundary(slice: &Wtf8, index: usize) {
/// Copied from core::str::raw::slice_unchecked
#[inline]
pub unsafe fn slice_unchecked(s: &Wtf8, begin: usize, end: usize) -> &Wtf8 {
// memory layout of a &[u8] and &Wtf8 are the same
Wtf8::from_bytes_unchecked(slice::from_raw_parts(s.bytes.as_ptr().add(begin), end - begin))
// SAFETY: memory layout of a &[u8] and &Wtf8 are the same
unsafe {
let len = end - begin;
let start = s.as_bytes().as_ptr().add(begin);
Wtf8::from_bytes_unchecked(slice::from_raw_parts(start, len))
}
}

/// Copied from core::str::raw::slice_error_fail
Loading