diff --git a/Cargo.toml b/Cargo.toml index 7060a608b6..7c2f1471ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,7 @@ implicit_clone = "deny" missing_errors_doc = "allow" # TODO review occurrences missing_panics_doc = "allow" # TODO review occurrences missing_safety_doc = "allow" # TODO review occurrences -mut_from_ref = "warn" # TODO review occurrences +mut_from_ref = "deny" precedence = "deny" ptr_as_ptr = "warn" # TODO review occurrences ptr_cast_constness = "warn" # TODO review occurrences diff --git a/src/header/bits_iovec/mod.rs b/src/header/bits_iovec/mod.rs index 4ce1ea904f..f9904df83d 100644 --- a/src/header/bits_iovec/mod.rs +++ b/src/header/bits_iovec/mod.rs @@ -15,6 +15,7 @@ pub struct iovec { } impl iovec { + #[expect(clippy::mut_from_ref)] unsafe fn to_slice(&self) -> &mut [u8] { unsafe { slice::from_raw_parts_mut(self.iov_base.cast::(), self.iov_len) } } @@ -23,6 +24,7 @@ impl iovec { pub unsafe fn gather(iovs: &[iovec]) -> Vec { let mut vec = Vec::new(); for iov in iovs.iter() { + // SAFETY: only a single mutable reference created vec.extend_from_slice(unsafe { iov.to_slice() }); } vec @@ -31,6 +33,7 @@ pub unsafe fn gather(iovs: &[iovec]) -> Vec { pub unsafe fn scatter(iovs: &[iovec], vec: Vec) { let mut i = 0; for iov in iovs.iter() { + // SAFETY: only a single mutable reference created let slice = unsafe { iov.to_slice() }; slice.copy_from_slice(&vec[i..][..slice.len()]); i += slice.len(); diff --git a/src/header/spawn/mod.rs b/src/header/spawn/mod.rs index 29e9cb3310..7dd42562c5 100644 --- a/src/header/spawn/mod.rs +++ b/src/header/spawn/mod.rs @@ -118,7 +118,7 @@ pub unsafe extern "C" fn posix_spawnp( return errno::ENOENT; } let path_env = unsafe { CStr::from_ptr(path_env) }; - for program_buf in PathSearchIter::new(&program.to_bytes(), &path_env) { + for program_buf in PathSearchIter::new(program.to_bytes(), &path_env) { // SAFETY: CStr::from_ptr().to_bytes() always stop at null, no need to check again let program_c = unsafe { CStr::from_bytes_with_nul_unchecked(program_buf.as_slice()) }; if Sys::access(program_c, F_OK).is_err() { diff --git a/src/header/unistd/mod.rs b/src/header/unistd/mod.rs index 1d1d8171f0..9628f84095 100644 --- a/src/header/unistd/mod.rs +++ b/src/header/unistd/mod.rs @@ -384,7 +384,7 @@ pub unsafe extern "C" fn execvp(file: *const c_char, argv: *const *mut c_char) - let path_env = unsafe { getenv(c"PATH".as_ptr()) }; if !path_env.is_null() { let path_env = unsafe { CStr::from_ptr(path_env) }; - for program_buf in PathSearchIter::new(&file.to_bytes(), &path_env) { + for program_buf in PathSearchIter::new(file.to_bytes(), &path_env) { // SAFETY: CStr::from_ptr().to_bytes() always stop at null, no need to check again let program_c = unsafe { CStr::from_bytes_with_nul_unchecked(program_buf.as_slice()) }; diff --git a/src/ld_so/linker.rs b/src/ld_so/linker.rs index 360584fa76..56193ff1ab 100644 --- a/src/ld_so/linker.rs +++ b/src/ld_so/linker.rs @@ -135,6 +135,7 @@ impl MmapFile { unsafe { core::slice::from_raw_parts(self.ptr.cast::(), self.size) } } + #[expect(clippy::mut_from_ref)] fn as_mut_slice(&self) -> &mut [u8] { unsafe { core::slice::from_raw_parts_mut(self.ptr.cast::(), self.size) } } diff --git a/src/platform/mod.rs b/src/platform/mod.rs index 71a323993c..5e5f4c62c8 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -321,8 +321,7 @@ pub unsafe fn get_auxvs(ptr: *const usize) -> Box<[[usize; 2]]> { // TODO: Find an auxv replacement for Redox's execv protocol #[cold] pub unsafe fn get_auxv_raw(ptr: *const usize, requested_kind: usize) -> Option { - unsafe { auxv_iter(ptr) } - .find_map(|[kind, value]| Some(value).filter(|_| kind == requested_kind)) + unsafe { auxv_iter(ptr) }.find_map(|[kind, value]| (kind == requested_kind).then_some(value)) } pub fn get_auxv(auxvs: &[[usize; 2]], key: usize) -> Option { auxvs diff --git a/src/raw_cell.rs b/src/raw_cell.rs index 998fccdca0..546498bb0e 100644 --- a/src/raw_cell.rs +++ b/src/raw_cell.rs @@ -33,6 +33,11 @@ impl RawCell { pub unsafe fn unsafe_set(&self, t: T) { unsafe { *self.inner.get() = t }; } + /// # Safety + /// This allows creation of multiple mutable references from an immutable + /// reference. Caller must ensure this is not called on the same `RawCell` + /// multiple times. + #[expect(clippy::mut_from_ref, reason = "documented safety usage")] #[inline] pub unsafe fn unsafe_mut(&self) -> &mut T { unsafe { &mut *self.inner.get() } diff --git a/src/sync/mutex.rs b/src/sync/mutex.rs index fc8cda2892..b404b48755 100644 --- a/src/sync/mutex.rs +++ b/src/sync/mutex.rs @@ -75,6 +75,12 @@ impl Mutex { /// it's up to you to unlock it after mutex. Returns the last atomic value /// on failure. You should probably not worry about this, it's used for /// internal optimizations. + /// + /// # Safety + /// This allows creation of multiple mutable references from an immutable + /// reference. Caller must ensure this is not called on the same `Mutex` + /// multiple times. + #[expect(clippy::mut_from_ref, reason = "documented safety usage")] pub unsafe fn manual_try_lock(&self) -> Result<&mut T, c_int> { if unsafe { manual_try_lock_generic(&self.lock) } { Ok(unsafe { &mut *self.content.get() }) @@ -85,6 +91,12 @@ impl Mutex { /// Lock the mutex, returning the inner content. After doing this, it's /// your responsibility to unlock it after usage. Mostly useful for FFI: /// Prefer normal .lock() where possible. + /// + /// # Safety + /// This allows creation of multiple mutable references from an immutable + /// reference. Caller must ensure this is not called on the same `Mutex` + /// multiple times. + #[expect(clippy::mut_from_ref, reason = "documented safety usage")] pub unsafe fn manual_lock(&self) -> &mut T { unsafe { manual_lock_generic(&self.lock) }; unsafe { &mut *self.content.get() }